diff options
Diffstat (limited to 'src')
141 files changed, 7014 insertions, 3972 deletions
diff --git a/src/common/arm64/native_clock.cpp b/src/common/arm64/native_clock.cpp index f437d7187..76ffb74ba 100644 --- a/src/common/arm64/native_clock.cpp +++ b/src/common/arm64/native_clock.cpp | |||
| @@ -30,27 +30,27 @@ NativeClock::NativeClock() { | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | std::chrono::nanoseconds NativeClock::GetTimeNS() const { | 32 | std::chrono::nanoseconds NativeClock::GetTimeNS() const { |
| 33 | return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)}; | 33 | return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)}; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | std::chrono::microseconds NativeClock::GetTimeUS() const { | 36 | std::chrono::microseconds NativeClock::GetTimeUS() const { |
| 37 | return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)}; | 37 | return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)}; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | std::chrono::milliseconds NativeClock::GetTimeMS() const { | 40 | std::chrono::milliseconds NativeClock::GetTimeMS() const { |
| 41 | return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)}; | 41 | return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)}; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | u64 NativeClock::GetCNTPCT() const { | 44 | s64 NativeClock::GetCNTPCT() const { |
| 45 | return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor); | 45 | return MultiplyHigh(GetUptime(), guest_cntfrq_factor); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | u64 NativeClock::GetGPUTick() const { | 48 | s64 NativeClock::GetGPUTick() const { |
| 49 | return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor); | 49 | return MultiplyHigh(GetUptime(), gputick_cntfrq_factor); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | u64 NativeClock::GetHostTicksNow() const { | 52 | s64 NativeClock::GetUptime() const { |
| 53 | u64 cntvct_el0 = 0; | 53 | s64 cntvct_el0 = 0; |
| 54 | asm volatile("dsb ish\n\t" | 54 | asm volatile("dsb ish\n\t" |
| 55 | "mrs %[cntvct_el0], cntvct_el0\n\t" | 55 | "mrs %[cntvct_el0], cntvct_el0\n\t" |
| 56 | "dsb ish\n\t" | 56 | "dsb ish\n\t" |
| @@ -58,15 +58,11 @@ u64 NativeClock::GetHostTicksNow() const { | |||
| 58 | return cntvct_el0; | 58 | return cntvct_el0; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | u64 NativeClock::GetHostTicksElapsed() const { | ||
| 62 | return GetHostTicksNow(); | ||
| 63 | } | ||
| 64 | |||
| 65 | bool NativeClock::IsNative() const { | 61 | bool NativeClock::IsNative() const { |
| 66 | return true; | 62 | return true; |
| 67 | } | 63 | } |
| 68 | 64 | ||
| 69 | u64 NativeClock::GetHostCNTFRQ() { | 65 | s64 NativeClock::GetHostCNTFRQ() { |
| 70 | u64 cntfrq_el0 = 0; | 66 | u64 cntfrq_el0 = 0; |
| 71 | std::string_view board{""}; | 67 | std::string_view board{""}; |
| 72 | #ifdef ANDROID | 68 | #ifdef ANDROID |
diff --git a/src/common/arm64/native_clock.h b/src/common/arm64/native_clock.h index a28b419f2..94bc1882e 100644 --- a/src/common/arm64/native_clock.h +++ b/src/common/arm64/native_clock.h | |||
| @@ -17,17 +17,15 @@ public: | |||
| 17 | 17 | ||
| 18 | std::chrono::milliseconds GetTimeMS() const override; | 18 | std::chrono::milliseconds GetTimeMS() const override; |
| 19 | 19 | ||
| 20 | u64 GetCNTPCT() const override; | 20 | s64 GetCNTPCT() const override; |
| 21 | 21 | ||
| 22 | u64 GetGPUTick() const override; | 22 | s64 GetGPUTick() const override; |
| 23 | 23 | ||
| 24 | u64 GetHostTicksNow() const override; | 24 | s64 GetUptime() const override; |
| 25 | |||
| 26 | u64 GetHostTicksElapsed() const override; | ||
| 27 | 25 | ||
| 28 | bool IsNative() const override; | 26 | bool IsNative() const override; |
| 29 | 27 | ||
| 30 | static u64 GetHostCNTFRQ(); | 28 | static s64 GetHostCNTFRQ(); |
| 31 | 29 | ||
| 32 | public: | 30 | public: |
| 33 | using FactorType = unsigned __int128; | 31 | using FactorType = unsigned __int128; |
diff --git a/src/common/memory_detect.h b/src/common/memory_detect.h index a345e6d28..c8f239aed 100644 --- a/src/common/memory_detect.h +++ b/src/common/memory_detect.h | |||
| @@ -18,4 +18,4 @@ struct MemoryInfo { | |||
| 18 | */ | 18 | */ |
| 19 | [[nodiscard]] const MemoryInfo& GetMemInfo(); | 19 | [[nodiscard]] const MemoryInfo& GetMemInfo(); |
| 20 | 20 | ||
| 21 | } // namespace Common \ No newline at end of file | 21 | } // namespace Common |
diff --git a/src/common/settings.h b/src/common/settings.h index 07dba53ab..16749ab68 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -419,9 +419,16 @@ struct Values { | |||
| 419 | linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true}; | 419 | linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true}; |
| 420 | SwitchableSetting<s64> custom_rtc{ | 420 | SwitchableSetting<s64> custom_rtc{ |
| 421 | linkage, 0, "custom_rtc", Category::System, Specialization::Time, | 421 | linkage, 0, "custom_rtc", Category::System, Specialization::Time, |
| 422 | true, true, &custom_rtc_enabled}; | 422 | false, true, &custom_rtc_enabled}; |
| 423 | // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` | 423 | SwitchableSetting<s64, true> custom_rtc_offset{linkage, |
| 424 | s64 custom_rtc_differential; | 424 | 0, |
| 425 | std::numeric_limits<int>::min(), | ||
| 426 | std::numeric_limits<int>::max(), | ||
| 427 | "custom_rtc_offset", | ||
| 428 | Category::System, | ||
| 429 | Specialization::Countable, | ||
| 430 | true, | ||
| 431 | true}; | ||
| 425 | SwitchableSetting<bool> rng_seed_enabled{ | 432 | SwitchableSetting<bool> rng_seed_enabled{ |
| 426 | linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true}; | 433 | linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true}; |
| 427 | SwitchableSetting<u32> rng_seed{ | 434 | SwitchableSetting<u32> rng_seed{ |
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp index 69e728a9d..f77df604f 100644 --- a/src/common/time_zone.cpp +++ b/src/common/time_zone.cpp | |||
| @@ -88,7 +88,17 @@ std::string FindSystemTimeZone() { | |||
| 88 | LOG_ERROR(Common, "Time zone {} not handled, defaulting to hour offset.", tz_index); | 88 | LOG_ERROR(Common, "Time zone {} not handled, defaulting to hour offset.", tz_index); |
| 89 | } | 89 | } |
| 90 | } | 90 | } |
| 91 | return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours)); | 91 | |
| 92 | // For some reason the Etc/GMT times are reversed. GMT+6 contains -21600 as its offset, | ||
| 93 | // -6 hours instead of +6 hours, so these signs are purposefully reversed to fix it. | ||
| 94 | std::string postfix{""}; | ||
| 95 | if (hours > 0) { | ||
| 96 | postfix = fmt::format("-{:d}", std::abs(hours)); | ||
| 97 | } else if (hours < 0) { | ||
| 98 | postfix = fmt::format("+{:d}", std::abs(hours)); | ||
| 99 | } | ||
| 100 | |||
| 101 | return fmt::format("Etc/GMT{:s}", postfix); | ||
| 92 | } | 102 | } |
| 93 | 103 | ||
| 94 | } // namespace Common::TimeZone | 104 | } // namespace Common::TimeZone |
diff --git a/src/common/uuid.h b/src/common/uuid.h index 7172ca165..81bfefbbb 100644 --- a/src/common/uuid.h +++ b/src/common/uuid.h | |||
| @@ -12,9 +12,8 @@ | |||
| 12 | namespace Common { | 12 | namespace Common { |
| 13 | 13 | ||
| 14 | struct UUID { | 14 | struct UUID { |
| 15 | std::array<u8, 0x10> uuid{}; | 15 | std::array<u8, 0x10> uuid; |
| 16 | 16 | ||
| 17 | /// Constructs an invalid UUID. | ||
| 18 | constexpr UUID() = default; | 17 | constexpr UUID() = default; |
| 19 | 18 | ||
| 20 | /// Constructs a UUID from a reference to a 128 bit array. | 19 | /// Constructs a UUID from a reference to a 128 bit array. |
| @@ -34,14 +33,6 @@ struct UUID { | |||
| 34 | */ | 33 | */ |
| 35 | explicit UUID(std::string_view uuid_string); | 34 | explicit UUID(std::string_view uuid_string); |
| 36 | 35 | ||
| 37 | ~UUID() = default; | ||
| 38 | |||
| 39 | constexpr UUID(const UUID&) noexcept = default; | ||
| 40 | constexpr UUID(UUID&&) noexcept = default; | ||
| 41 | |||
| 42 | constexpr UUID& operator=(const UUID&) noexcept = default; | ||
| 43 | constexpr UUID& operator=(UUID&&) noexcept = default; | ||
| 44 | |||
| 45 | /** | 36 | /** |
| 46 | * Returns whether the stored UUID is valid or not. | 37 | * Returns whether the stored UUID is valid or not. |
| 47 | * | 38 | * |
| @@ -121,6 +112,7 @@ struct UUID { | |||
| 121 | friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; | 112 | friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; |
| 122 | }; | 113 | }; |
| 123 | static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size."); | 114 | static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size."); |
| 115 | static_assert(std::is_trivial_v<UUID>); | ||
| 124 | 116 | ||
| 125 | /// An invalid UUID. This UUID has all its bytes set to 0. | 117 | /// An invalid UUID. This UUID has all its bytes set to 0. |
| 126 | constexpr UUID InvalidUUID = {}; | 118 | constexpr UUID InvalidUUID = {}; |
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 012fdc1e0..e14bf3e65 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp | |||
| @@ -18,42 +18,40 @@ namespace Common { | |||
| 18 | 18 | ||
| 19 | class StandardWallClock final : public WallClock { | 19 | class StandardWallClock final : public WallClock { |
| 20 | public: | 20 | public: |
| 21 | explicit StandardWallClock() : start_time{SteadyClock::Now()} {} | 21 | explicit StandardWallClock() {} |
| 22 | 22 | ||
| 23 | std::chrono::nanoseconds GetTimeNS() const override { | 23 | std::chrono::nanoseconds GetTimeNS() const override { |
| 24 | return SteadyClock::Now() - start_time; | 24 | return std::chrono::duration_cast<std::chrono::nanoseconds>( |
| 25 | std::chrono::system_clock::now().time_since_epoch()); | ||
| 25 | } | 26 | } |
| 26 | 27 | ||
| 27 | std::chrono::microseconds GetTimeUS() const override { | 28 | std::chrono::microseconds GetTimeUS() const override { |
| 28 | return static_cast<std::chrono::microseconds>(GetHostTicksElapsed() / NsToUsRatio::den); | 29 | return std::chrono::duration_cast<std::chrono::microseconds>( |
| 30 | std::chrono::system_clock::now().time_since_epoch()); | ||
| 29 | } | 31 | } |
| 30 | 32 | ||
| 31 | std::chrono::milliseconds GetTimeMS() const override { | 33 | std::chrono::milliseconds GetTimeMS() const override { |
| 32 | return static_cast<std::chrono::milliseconds>(GetHostTicksElapsed() / NsToMsRatio::den); | 34 | return std::chrono::duration_cast<std::chrono::milliseconds>( |
| 35 | std::chrono::system_clock::now().time_since_epoch()); | ||
| 33 | } | 36 | } |
| 34 | 37 | ||
| 35 | u64 GetCNTPCT() const override { | 38 | s64 GetCNTPCT() const override { |
| 36 | return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; | 39 | return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; |
| 37 | } | 40 | } |
| 38 | 41 | ||
| 39 | u64 GetGPUTick() const override { | 42 | s64 GetGPUTick() const override { |
| 40 | return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; | 43 | return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; |
| 41 | } | 44 | } |
| 42 | 45 | ||
| 43 | u64 GetHostTicksNow() const override { | 46 | s64 GetUptime() const override { |
| 44 | return static_cast<u64>(SteadyClock::Now().time_since_epoch().count()); | 47 | return std::chrono::duration_cast<std::chrono::nanoseconds>( |
| 45 | } | 48 | std::chrono::steady_clock::now().time_since_epoch()) |
| 46 | 49 | .count(); | |
| 47 | u64 GetHostTicksElapsed() const override { | ||
| 48 | return static_cast<u64>(GetTimeNS().count()); | ||
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | bool IsNative() const override { | 52 | bool IsNative() const override { |
| 52 | return false; | 53 | return false; |
| 53 | } | 54 | } |
| 54 | |||
| 55 | private: | ||
| 56 | SteadyClock::time_point start_time; | ||
| 57 | }; | 55 | }; |
| 58 | 56 | ||
| 59 | std::unique_ptr<WallClock> CreateOptimalClock() { | 57 | std::unique_ptr<WallClock> CreateOptimalClock() { |
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index f45d3d8c5..3a0c43909 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h | |||
| @@ -29,16 +29,13 @@ public: | |||
| 29 | virtual std::chrono::milliseconds GetTimeMS() const = 0; | 29 | virtual std::chrono::milliseconds GetTimeMS() const = 0; |
| 30 | 30 | ||
| 31 | /// @returns The guest CNTPCT ticks since the construction of this clock. | 31 | /// @returns The guest CNTPCT ticks since the construction of this clock. |
| 32 | virtual u64 GetCNTPCT() const = 0; | 32 | virtual s64 GetCNTPCT() const = 0; |
| 33 | 33 | ||
| 34 | /// @returns The guest GPU ticks since the construction of this clock. | 34 | /// @returns The guest GPU ticks since the construction of this clock. |
| 35 | virtual u64 GetGPUTick() const = 0; | 35 | virtual s64 GetGPUTick() const = 0; |
| 36 | 36 | ||
| 37 | /// @returns The raw host timer ticks since an indeterminate epoch. | 37 | /// @returns The raw host timer ticks since an indeterminate epoch. |
| 38 | virtual u64 GetHostTicksNow() const = 0; | 38 | virtual s64 GetUptime() const = 0; |
| 39 | |||
| 40 | /// @returns The raw host timer ticks since the construction of this clock. | ||
| 41 | virtual u64 GetHostTicksElapsed() const = 0; | ||
| 42 | 39 | ||
| 43 | /// @returns Whether the clock directly uses the host's hardware clock. | 40 | /// @returns Whether the clock directly uses the host's hardware clock. |
| 44 | virtual bool IsNative() const = 0; | 41 | virtual bool IsNative() const = 0; |
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 7d2a26bd9..d2d27fafe 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -8,39 +8,35 @@ | |||
| 8 | namespace Common::X64 { | 8 | namespace Common::X64 { |
| 9 | 9 | ||
| 10 | NativeClock::NativeClock(u64 rdtsc_frequency_) | 10 | NativeClock::NativeClock(u64 rdtsc_frequency_) |
| 11 | : start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_}, | 11 | : rdtsc_frequency{rdtsc_frequency_}, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, |
| 12 | ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)}, | 12 | rdtsc_frequency)}, |
| 13 | us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, | 13 | us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, |
| 14 | ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, | 14 | ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, |
| 15 | cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, | 15 | cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, |
| 16 | gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} | 16 | gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} |
| 17 | 17 | ||
| 18 | std::chrono::nanoseconds NativeClock::GetTimeNS() const { | 18 | std::chrono::nanoseconds NativeClock::GetTimeNS() const { |
| 19 | return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)}; | 19 | return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)}; |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | std::chrono::microseconds NativeClock::GetTimeUS() const { | 22 | std::chrono::microseconds NativeClock::GetTimeUS() const { |
| 23 | return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)}; | 23 | return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)}; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | std::chrono::milliseconds NativeClock::GetTimeMS() const { | 26 | std::chrono::milliseconds NativeClock::GetTimeMS() const { |
| 27 | return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)}; | 27 | return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)}; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | u64 NativeClock::GetCNTPCT() const { | 30 | s64 NativeClock::GetCNTPCT() const { |
| 31 | return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor); | 31 | return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | u64 NativeClock::GetGPUTick() const { | 34 | s64 NativeClock::GetGPUTick() const { |
| 35 | return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor); | 35 | return MultiplyHigh(GetUptime(), gputick_rdtsc_factor); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | u64 NativeClock::GetHostTicksNow() const { | 38 | s64 NativeClock::GetUptime() const { |
| 39 | return FencedRDTSC(); | 39 | return static_cast<s64>(FencedRDTSC()); |
| 40 | } | ||
| 41 | |||
| 42 | u64 NativeClock::GetHostTicksElapsed() const { | ||
| 43 | return FencedRDTSC() - start_ticks; | ||
| 44 | } | 40 | } |
| 45 | 41 | ||
| 46 | bool NativeClock::IsNative() const { | 42 | bool NativeClock::IsNative() const { |
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 334415eff..b2629b031 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h | |||
| @@ -17,18 +17,15 @@ public: | |||
| 17 | 17 | ||
| 18 | std::chrono::milliseconds GetTimeMS() const override; | 18 | std::chrono::milliseconds GetTimeMS() const override; |
| 19 | 19 | ||
| 20 | u64 GetCNTPCT() const override; | 20 | s64 GetCNTPCT() const override; |
| 21 | 21 | ||
| 22 | u64 GetGPUTick() const override; | 22 | s64 GetGPUTick() const override; |
| 23 | 23 | ||
| 24 | u64 GetHostTicksNow() const override; | 24 | s64 GetUptime() const override; |
| 25 | |||
| 26 | u64 GetHostTicksElapsed() const override; | ||
| 27 | 25 | ||
| 28 | bool IsNative() const override; | 26 | bool IsNative() const override; |
| 29 | 27 | ||
| 30 | private: | 28 | private: |
| 31 | u64 start_ticks; | ||
| 32 | u64 rdtsc_frequency; | 29 | u64 rdtsc_frequency; |
| 33 | 30 | ||
| 34 | u64 ns_rdtsc_factor; | 31 | u64 ns_rdtsc_factor; |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4ff2c1bb7..f75b5e10a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -515,6 +515,24 @@ add_library(core STATIC | |||
| 515 | hle/service/glue/glue_manager.h | 515 | hle/service/glue/glue_manager.h |
| 516 | hle/service/glue/notif.cpp | 516 | hle/service/glue/notif.cpp |
| 517 | hle/service/glue/notif.h | 517 | hle/service/glue/notif.h |
| 518 | hle/service/glue/time/alarm_worker.cpp | ||
| 519 | hle/service/glue/time/alarm_worker.h | ||
| 520 | hle/service/glue/time/file_timestamp_worker.cpp | ||
| 521 | hle/service/glue/time/file_timestamp_worker.h | ||
| 522 | hle/service/glue/time/manager.cpp | ||
| 523 | hle/service/glue/time/manager.h | ||
| 524 | hle/service/glue/time/pm_state_change_handler.cpp | ||
| 525 | hle/service/glue/time/pm_state_change_handler.h | ||
| 526 | hle/service/glue/time/standard_steady_clock_resource.cpp | ||
| 527 | hle/service/glue/time/standard_steady_clock_resource.h | ||
| 528 | hle/service/glue/time/static.cpp | ||
| 529 | hle/service/glue/time/static.h | ||
| 530 | hle/service/glue/time/time_zone.cpp | ||
| 531 | hle/service/glue/time/time_zone.h | ||
| 532 | hle/service/glue/time/time_zone_binary.cpp | ||
| 533 | hle/service/glue/time/time_zone_binary.h | ||
| 534 | hle/service/glue/time/worker.cpp | ||
| 535 | hle/service/glue/time/worker.h | ||
| 518 | hle/service/grc/grc.cpp | 536 | hle/service/grc/grc.cpp |
| 519 | hle/service/grc/grc.h | 537 | hle/service/grc/grc.h |
| 520 | hle/service/hid/hid.cpp | 538 | hle/service/hid/hid.cpp |
| @@ -693,6 +711,46 @@ add_library(core STATIC | |||
| 693 | hle/service/prepo/prepo.h | 711 | hle/service/prepo/prepo.h |
| 694 | hle/service/psc/psc.cpp | 712 | hle/service/psc/psc.cpp |
| 695 | hle/service/psc/psc.h | 713 | hle/service/psc/psc.h |
| 714 | hle/service/psc/time/alarms.cpp | ||
| 715 | hle/service/psc/time/alarms.h | ||
| 716 | hle/service/psc/time/clocks/context_writers.cpp | ||
| 717 | hle/service/psc/time/clocks/context_writers.h | ||
| 718 | hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h | ||
| 719 | hle/service/psc/time/clocks/standard_local_system_clock_core.cpp | ||
| 720 | hle/service/psc/time/clocks/standard_local_system_clock_core.h | ||
| 721 | hle/service/psc/time/clocks/standard_network_system_clock_core.cpp | ||
| 722 | hle/service/psc/time/clocks/standard_network_system_clock_core.h | ||
| 723 | hle/service/psc/time/clocks/standard_steady_clock_core.cpp | ||
| 724 | hle/service/psc/time/clocks/standard_steady_clock_core.h | ||
| 725 | hle/service/psc/time/clocks/standard_user_system_clock_core.cpp | ||
| 726 | hle/service/psc/time/clocks/standard_user_system_clock_core.h | ||
| 727 | hle/service/psc/time/clocks/steady_clock_core.h | ||
| 728 | hle/service/psc/time/clocks/system_clock_core.cpp | ||
| 729 | hle/service/psc/time/clocks/system_clock_core.h | ||
| 730 | hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp | ||
| 731 | hle/service/psc/time/clocks/tick_based_steady_clock_core.h | ||
| 732 | hle/service/psc/time/common.cpp | ||
| 733 | hle/service/psc/time/common.h | ||
| 734 | hle/service/psc/time/errors.h | ||
| 735 | hle/service/psc/time/shared_memory.cpp | ||
| 736 | hle/service/psc/time/shared_memory.h | ||
| 737 | hle/service/psc/time/static.cpp | ||
| 738 | hle/service/psc/time/static.h | ||
| 739 | hle/service/psc/time/manager.h | ||
| 740 | hle/service/psc/time/power_state_service.cpp | ||
| 741 | hle/service/psc/time/power_state_service.h | ||
| 742 | hle/service/psc/time/service_manager.cpp | ||
| 743 | hle/service/psc/time/service_manager.h | ||
| 744 | hle/service/psc/time/steady_clock.cpp | ||
| 745 | hle/service/psc/time/steady_clock.h | ||
| 746 | hle/service/psc/time/system_clock.cpp | ||
| 747 | hle/service/psc/time/system_clock.h | ||
| 748 | hle/service/psc/time/time_zone.cpp | ||
| 749 | hle/service/psc/time/time_zone.h | ||
| 750 | hle/service/psc/time/time_zone_service.cpp | ||
| 751 | hle/service/psc/time/time_zone_service.h | ||
| 752 | hle/service/psc/time/power_state_request_manager.cpp | ||
| 753 | hle/service/psc/time/power_state_request_manager.h | ||
| 696 | hle/service/ptm/psm.cpp | 754 | hle/service/ptm/psm.cpp |
| 697 | hle/service/ptm/psm.h | 755 | hle/service/ptm/psm.h |
| 698 | hle/service/ptm/ptm.cpp | 756 | hle/service/ptm/ptm.cpp |
| @@ -760,40 +818,6 @@ add_library(core STATIC | |||
| 760 | hle/service/ssl/ssl.cpp | 818 | hle/service/ssl/ssl.cpp |
| 761 | hle/service/ssl/ssl.h | 819 | hle/service/ssl/ssl.h |
| 762 | hle/service/ssl/ssl_backend.h | 820 | hle/service/ssl/ssl_backend.h |
| 763 | hle/service/time/clock_types.h | ||
| 764 | hle/service/time/ephemeral_network_system_clock_context_writer.h | ||
| 765 | hle/service/time/ephemeral_network_system_clock_core.h | ||
| 766 | hle/service/time/errors.h | ||
| 767 | hle/service/time/local_system_clock_context_writer.h | ||
| 768 | hle/service/time/network_system_clock_context_writer.h | ||
| 769 | hle/service/time/standard_local_system_clock_core.h | ||
| 770 | hle/service/time/standard_network_system_clock_core.h | ||
| 771 | hle/service/time/standard_steady_clock_core.cpp | ||
| 772 | hle/service/time/standard_steady_clock_core.h | ||
| 773 | hle/service/time/standard_user_system_clock_core.cpp | ||
| 774 | hle/service/time/standard_user_system_clock_core.h | ||
| 775 | hle/service/time/steady_clock_core.h | ||
| 776 | hle/service/time/system_clock_context_update_callback.cpp | ||
| 777 | hle/service/time/system_clock_context_update_callback.h | ||
| 778 | hle/service/time/system_clock_core.cpp | ||
| 779 | hle/service/time/system_clock_core.h | ||
| 780 | hle/service/time/tick_based_steady_clock_core.cpp | ||
| 781 | hle/service/time/tick_based_steady_clock_core.h | ||
| 782 | hle/service/time/time.cpp | ||
| 783 | hle/service/time/time.h | ||
| 784 | hle/service/time/time_interface.cpp | ||
| 785 | hle/service/time/time_interface.h | ||
| 786 | hle/service/time/time_manager.cpp | ||
| 787 | hle/service/time/time_manager.h | ||
| 788 | hle/service/time/time_sharedmemory.cpp | ||
| 789 | hle/service/time/time_sharedmemory.h | ||
| 790 | hle/service/time/time_zone_content_manager.cpp | ||
| 791 | hle/service/time/time_zone_content_manager.h | ||
| 792 | hle/service/time/time_zone_manager.cpp | ||
| 793 | hle/service/time/time_zone_manager.h | ||
| 794 | hle/service/time/time_zone_service.cpp | ||
| 795 | hle/service/time/time_zone_service.h | ||
| 796 | hle/service/time/time_zone_types.h | ||
| 797 | hle/service/usb/usb.cpp | 821 | hle/service/usb/usb.cpp |
| 798 | hle/service/usb/usb.h | 822 | hle/service/usb/usb.h |
| 799 | hle/service/vi/display/vi_display.cpp | 823 | hle/service/vi/display/vi_display.cpp |
| @@ -874,7 +898,7 @@ endif() | |||
| 874 | 898 | ||
| 875 | create_target_directory_groups(core) | 899 | create_target_directory_groups(core) |
| 876 | 900 | ||
| 877 | target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb) | 901 | target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz) |
| 878 | target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) | 902 | target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) |
| 879 | if (MINGW) | 903 | if (MINGW) |
| 880 | target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) | 904 | target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 2392fe136..dd9de948c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -40,9 +40,14 @@ | |||
| 40 | #include "core/hle/service/apm/apm_controller.h" | 40 | #include "core/hle/service/apm/apm_controller.h" |
| 41 | #include "core/hle/service/filesystem/filesystem.h" | 41 | #include "core/hle/service/filesystem/filesystem.h" |
| 42 | #include "core/hle/service/glue/glue_manager.h" | 42 | #include "core/hle/service/glue/glue_manager.h" |
| 43 | #include "core/hle/service/glue/time/static.h" | ||
| 44 | #include "core/hle/service/psc/time/static.h" | ||
| 45 | #include "core/hle/service/psc/time/steady_clock.h" | ||
| 46 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 47 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 43 | #include "core/hle/service/service.h" | 48 | #include "core/hle/service/service.h" |
| 49 | #include "core/hle/service/set/system_settings_server.h" | ||
| 44 | #include "core/hle/service/sm/sm.h" | 50 | #include "core/hle/service/sm/sm.h" |
| 45 | #include "core/hle/service/time/time_manager.h" | ||
| 46 | #include "core/internal_network/network.h" | 51 | #include "core/internal_network/network.h" |
| 47 | #include "core/loader/loader.h" | 52 | #include "core/loader/loader.h" |
| 48 | #include "core/memory.h" | 53 | #include "core/memory.h" |
| @@ -130,8 +135,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 130 | 135 | ||
| 131 | struct System::Impl { | 136 | struct System::Impl { |
| 132 | explicit Impl(System& system) | 137 | explicit Impl(System& system) |
| 133 | : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, | 138 | : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, |
| 134 | reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {} | 139 | cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {} |
| 135 | 140 | ||
| 136 | void Initialize(System& system) { | 141 | void Initialize(System& system) { |
| 137 | device_memory = std::make_unique<Core::DeviceMemory>(); | 142 | device_memory = std::make_unique<Core::DeviceMemory>(); |
| @@ -143,8 +148,6 @@ struct System::Impl { | |||
| 143 | core_timing.SetMulticore(is_multicore); | 148 | core_timing.SetMulticore(is_multicore); |
| 144 | core_timing.Initialize([&system]() { system.RegisterHostThread(); }); | 149 | core_timing.Initialize([&system]() { system.RegisterHostThread(); }); |
| 145 | 150 | ||
| 146 | RefreshTime(); | ||
| 147 | |||
| 148 | // Create a default fs if one doesn't already exist. | 151 | // Create a default fs if one doesn't already exist. |
| 149 | if (virtual_filesystem == nullptr) { | 152 | if (virtual_filesystem == nullptr) { |
| 150 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); | 153 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); |
| @@ -182,14 +185,57 @@ struct System::Impl { | |||
| 182 | Initialize(system); | 185 | Initialize(system); |
| 183 | } | 186 | } |
| 184 | 187 | ||
| 185 | void RefreshTime() { | 188 | void RefreshTime(System& system) { |
| 189 | if (!system.IsPoweredOn()) { | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | |||
| 193 | auto settings_service = | ||
| 194 | system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", | ||
| 195 | true); | ||
| 196 | auto static_service_a = | ||
| 197 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:a", true); | ||
| 198 | |||
| 199 | auto static_service_s = | ||
| 200 | system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:s", true); | ||
| 201 | |||
| 202 | std::shared_ptr<Service::PSC::Time::SystemClock> user_clock; | ||
| 203 | static_service_a->GetStandardUserSystemClock(user_clock); | ||
| 204 | |||
| 205 | std::shared_ptr<Service::PSC::Time::SystemClock> local_clock; | ||
| 206 | static_service_a->GetStandardLocalSystemClock(local_clock); | ||
| 207 | |||
| 208 | std::shared_ptr<Service::PSC::Time::SystemClock> network_clock; | ||
| 209 | static_service_s->GetStandardNetworkSystemClock(network_clock); | ||
| 210 | |||
| 211 | std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service; | ||
| 212 | static_service_a->GetTimeZoneService(timezone_service); | ||
| 213 | |||
| 214 | Service::PSC::Time::LocationName name{}; | ||
| 215 | auto new_name = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); | ||
| 216 | std::memcpy(name.name.data(), new_name.data(), std::min(name.name.size(), new_name.size())); | ||
| 217 | |||
| 218 | timezone_service->SetDeviceLocation(name); | ||
| 219 | |||
| 220 | u64 time_offset = 0; | ||
| 221 | if (Settings::values.custom_rtc_enabled) { | ||
| 222 | time_offset = Settings::values.custom_rtc_offset.GetValue(); | ||
| 223 | } | ||
| 224 | |||
| 186 | const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); | 225 | const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); |
| 187 | const auto current_time = | 226 | const u64 current_time = |
| 188 | std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); | 227 | +std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); |
| 189 | Settings::values.custom_rtc_differential = | 228 | const u64 new_time = current_time + time_offset; |
| 190 | (Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue() | 229 | |
| 191 | : current_time) - | 230 | Service::PSC::Time::SystemClockContext context{}; |
| 192 | current_time; | 231 | settings_service->SetUserSystemClockContext(context); |
| 232 | user_clock->SetCurrentTime(new_time); | ||
| 233 | |||
| 234 | local_clock->SetCurrentTime(new_time); | ||
| 235 | |||
| 236 | network_clock->GetSystemClockContext(context); | ||
| 237 | settings_service->SetNetworkSystemClockContext(context); | ||
| 238 | network_clock->SetCurrentTime(new_time); | ||
| 193 | } | 239 | } |
| 194 | 240 | ||
| 195 | void Run() { | 241 | void Run() { |
| @@ -265,9 +311,6 @@ struct System::Impl { | |||
| 265 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); | 311 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); |
| 266 | services = std::make_unique<Service::Services>(service_manager, system); | 312 | services = std::make_unique<Service::Services>(service_manager, system); |
| 267 | 313 | ||
| 268 | // Initialize time manager, which must happen after kernel is created | ||
| 269 | time_manager.Initialize(); | ||
| 270 | |||
| 271 | is_powered_on = true; | 314 | is_powered_on = true; |
| 272 | exit_locked = false; | 315 | exit_locked = false; |
| 273 | exit_requested = false; | 316 | exit_requested = false; |
| @@ -417,7 +460,6 @@ struct System::Impl { | |||
| 417 | fs_controller.Reset(); | 460 | fs_controller.Reset(); |
| 418 | cheat_engine.reset(); | 461 | cheat_engine.reset(); |
| 419 | telemetry_session.reset(); | 462 | telemetry_session.reset(); |
| 420 | time_manager.Shutdown(); | ||
| 421 | core_timing.ClearPendingEvents(); | 463 | core_timing.ClearPendingEvents(); |
| 422 | app_loader.reset(); | 464 | app_loader.reset(); |
| 423 | audio_core.reset(); | 465 | audio_core.reset(); |
| @@ -533,7 +575,6 @@ struct System::Impl { | |||
| 533 | /// Service State | 575 | /// Service State |
| 534 | Service::Glue::ARPManager arp_manager; | 576 | Service::Glue::ARPManager arp_manager; |
| 535 | Service::Account::ProfileManager profile_manager; | 577 | Service::Account::ProfileManager profile_manager; |
| 536 | Service::Time::TimeManager time_manager; | ||
| 537 | 578 | ||
| 538 | /// Service manager | 579 | /// Service manager |
| 539 | std::shared_ptr<Service::SM::ServiceManager> service_manager; | 580 | std::shared_ptr<Service::SM::ServiceManager> service_manager; |
| @@ -911,14 +952,6 @@ const Service::Account::ProfileManager& System::GetProfileManager() const { | |||
| 911 | return impl->profile_manager; | 952 | return impl->profile_manager; |
| 912 | } | 953 | } |
| 913 | 954 | ||
| 914 | Service::Time::TimeManager& System::GetTimeManager() { | ||
| 915 | return impl->time_manager; | ||
| 916 | } | ||
| 917 | |||
| 918 | const Service::Time::TimeManager& System::GetTimeManager() const { | ||
| 919 | return impl->time_manager; | ||
| 920 | } | ||
| 921 | |||
| 922 | void System::SetExitLocked(bool locked) { | 955 | void System::SetExitLocked(bool locked) { |
| 923 | impl->exit_locked = locked; | 956 | impl->exit_locked = locked; |
| 924 | } | 957 | } |
| @@ -1030,13 +1063,9 @@ void System::Exit() { | |||
| 1030 | } | 1063 | } |
| 1031 | 1064 | ||
| 1032 | void System::ApplySettings() { | 1065 | void System::ApplySettings() { |
| 1033 | impl->RefreshTime(); | 1066 | impl->RefreshTime(*this); |
| 1034 | 1067 | ||
| 1035 | if (IsPoweredOn()) { | 1068 | if (IsPoweredOn()) { |
| 1036 | if (Settings::values.custom_rtc_enabled) { | ||
| 1037 | const s64 posix_time{Settings::values.custom_rtc.GetValue()}; | ||
| 1038 | GetTimeManager().UpdateLocalSystemClockTime(posix_time); | ||
| 1039 | } | ||
| 1040 | Renderer().RefreshBaseSettings(); | 1069 | Renderer().RefreshBaseSettings(); |
| 1041 | } | 1070 | } |
| 1042 | } | 1071 | } |
diff --git a/src/core/core.h b/src/core/core.h index 80446f385..183410602 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -73,10 +73,6 @@ namespace SM { | |||
| 73 | class ServiceManager; | 73 | class ServiceManager; |
| 74 | } // namespace SM | 74 | } // namespace SM |
| 75 | 75 | ||
| 76 | namespace Time { | ||
| 77 | class TimeManager; | ||
| 78 | } // namespace Time | ||
| 79 | |||
| 80 | } // namespace Service | 76 | } // namespace Service |
| 81 | 77 | ||
| 82 | namespace Tegra { | 78 | namespace Tegra { |
| @@ -381,9 +377,6 @@ public: | |||
| 381 | [[nodiscard]] Service::Account::ProfileManager& GetProfileManager(); | 377 | [[nodiscard]] Service::Account::ProfileManager& GetProfileManager(); |
| 382 | [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const; | 378 | [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const; |
| 383 | 379 | ||
| 384 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); | ||
| 385 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; | ||
| 386 | |||
| 387 | [[nodiscard]] Core::Debugger& GetDebugger(); | 380 | [[nodiscard]] Core::Debugger& GetDebugger(); |
| 388 | [[nodiscard]] const Core::Debugger& GetDebugger() const; | 381 | [[nodiscard]] const Core::Debugger& GetDebugger() const; |
| 389 | 382 | ||
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index fc536413b..1abfa920c 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -157,7 +157,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, | |||
| 157 | } | 157 | } |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | for (auto h : to_remove) { | 160 | for (auto& h : to_remove) { |
| 161 | event_queue.erase(h); | 161 | event_queue.erase(h); |
| 162 | } | 162 | } |
| 163 | 163 | ||
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp index 6abac793b..b53eef877 100644 --- a/src/core/file_sys/system_archive/system_archive.cpp +++ b/src/core/file_sys/system_archive/system_archive.cpp | |||
| @@ -67,25 +67,29 @@ constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHI | |||
| 67 | }}; | 67 | }}; |
| 68 | 68 | ||
| 69 | VirtualFile SynthesizeSystemArchive(const u64 title_id) { | 69 | VirtualFile SynthesizeSystemArchive(const u64 title_id) { |
| 70 | if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) | 70 | if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) { |
| 71 | return nullptr; | 71 | return nullptr; |
| 72 | } | ||
| 72 | 73 | ||
| 73 | const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID]; | 74 | const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID]; |
| 74 | 75 | ||
| 75 | LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id); | 76 | LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id); |
| 76 | 77 | ||
| 77 | if (desc.supplier == nullptr) | 78 | if (desc.supplier == nullptr) { |
| 78 | return nullptr; | 79 | return nullptr; |
| 80 | } | ||
| 79 | 81 | ||
| 80 | const auto dir = desc.supplier(); | 82 | const auto dir = desc.supplier(); |
| 81 | 83 | ||
| 82 | if (dir == nullptr) | 84 | if (dir == nullptr) { |
| 83 | return nullptr; | 85 | return nullptr; |
| 86 | } | ||
| 84 | 87 | ||
| 85 | const auto romfs = CreateRomFS(dir); | 88 | const auto romfs = CreateRomFS(dir); |
| 86 | 89 | ||
| 87 | if (romfs == nullptr) | 90 | if (romfs == nullptr) { |
| 88 | return nullptr; | 91 | return nullptr; |
| 92 | } | ||
| 89 | 93 | ||
| 90 | LOG_INFO(Service_FS, " - System archive generation successful!"); | 94 | LOG_INFO(Service_FS, " - System archive generation successful!"); |
| 91 | return romfs; | 95 | return romfs; |
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp index 7c17bbefa..d4d2eae76 100644 --- a/src/core/file_sys/system_archive/time_zone_binary.cpp +++ b/src/core/file_sys/system_archive/time_zone_binary.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | #include "common/swap.h" | 6 | #include "common/swap.h" |
| 7 | #include "core/file_sys/system_archive/time_zone_binary.h" | 7 | #include "core/file_sys/system_archive/time_zone_binary.h" |
| 8 | #include "core/file_sys/vfs_vector.h" | 8 | #include "core/file_sys/vfs_vector.h" |
| 9 | #include "core/hle/service/time/time_zone_types.h" | ||
| 10 | 9 | ||
| 11 | #include "nx_tzdb.h" | 10 | #include "nx_tzdb.h" |
| 12 | 11 | ||
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 261fc204c..e3b8ecf3e 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp | |||
| @@ -10,8 +10,10 @@ | |||
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/hle/service/caps/caps_manager.h" | 11 | #include "core/hle/service/caps/caps_manager.h" |
| 12 | #include "core/hle/service/caps/caps_result.h" | 12 | #include "core/hle/service/caps/caps_result.h" |
| 13 | #include "core/hle/service/time/time_manager.h" | 13 | #include "core/hle/service/glue/time/static.h" |
| 14 | #include "core/hle/service/time/time_zone_content_manager.h" | 14 | #include "core/hle/service/psc/time/system_clock.h" |
| 15 | #include "core/hle/service/service.h" | ||
| 16 | #include "core/hle/service/sm/sm.h" | ||
| 15 | 17 | ||
| 16 | namespace Service::Capture { | 18 | namespace Service::Capture { |
| 17 | 19 | ||
| @@ -239,10 +241,15 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, | |||
| 239 | const ApplicationData& app_data, std::span<const u8> image_data, | 241 | const ApplicationData& app_data, std::span<const u8> image_data, |
| 240 | u64 aruid) { | 242 | u64 aruid) { |
| 241 | const u64 title_id = system.GetApplicationProcessProgramID(); | 243 | const u64 title_id = system.GetApplicationProcessProgramID(); |
| 242 | const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); | 244 | |
| 245 | auto static_service = | ||
| 246 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); | ||
| 247 | |||
| 248 | std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{}; | ||
| 249 | static_service->GetStandardUserSystemClock(user_clock); | ||
| 243 | 250 | ||
| 244 | s64 posix_time{}; | 251 | s64 posix_time{}; |
| 245 | Result result = user_clock.GetCurrentTime(system, posix_time); | 252 | auto result = user_clock->GetCurrentTime(posix_time); |
| 246 | 253 | ||
| 247 | if (result.IsError()) { | 254 | if (result.IsError()) { |
| 248 | return result; | 255 | return result; |
| @@ -257,10 +264,14 @@ Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, | |||
| 257 | const ScreenShotAttribute& attribute, | 264 | const ScreenShotAttribute& attribute, |
| 258 | const AlbumFileId& file_id, | 265 | const AlbumFileId& file_id, |
| 259 | std::span<const u8> image_data) { | 266 | std::span<const u8> image_data) { |
| 260 | const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); | 267 | auto static_service = |
| 268 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); | ||
| 269 | |||
| 270 | std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{}; | ||
| 271 | static_service->GetStandardUserSystemClock(user_clock); | ||
| 261 | 272 | ||
| 262 | s64 posix_time{}; | 273 | s64 posix_time{}; |
| 263 | Result result = user_clock.GetCurrentTime(system, posix_time); | 274 | auto result = user_clock->GetCurrentTime(posix_time); |
| 264 | 275 | ||
| 265 | if (result.IsError()) { | 276 | if (result.IsError()) { |
| 266 | return result; | 277 | return result; |
| @@ -455,19 +466,23 @@ Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const | |||
| 455 | } | 466 | } |
| 456 | 467 | ||
| 457 | AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { | 468 | AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { |
| 458 | Time::TimeZone::CalendarInfo calendar_date{}; | 469 | auto static_service = |
| 459 | const auto& time_zone_manager = | 470 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); |
| 460 | system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); | 471 | |
| 472 | std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{}; | ||
| 473 | static_service->GetTimeZoneService(timezone_service); | ||
| 461 | 474 | ||
| 462 | time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date); | 475 | Service::PSC::Time::CalendarTime calendar_time{}; |
| 476 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 477 | timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time); | ||
| 463 | 478 | ||
| 464 | return { | 479 | return { |
| 465 | .year = calendar_date.time.year, | 480 | .year = calendar_time.year, |
| 466 | .month = calendar_date.time.month, | 481 | .month = calendar_time.month, |
| 467 | .day = calendar_date.time.day, | 482 | .day = calendar_time.day, |
| 468 | .hour = calendar_date.time.hour, | 483 | .hour = calendar_time.hour, |
| 469 | .minute = calendar_date.time.minute, | 484 | .minute = calendar_time.minute, |
| 470 | .second = calendar_date.time.second, | 485 | .second = calendar_time.second, |
| 471 | .unique_id = 0, | 486 | .unique_id = 0, |
| 472 | }; | 487 | }; |
| 473 | } | 488 | } |
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index 993c3d21d..10376bfac 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp | |||
| @@ -8,6 +8,9 @@ | |||
| 8 | #include "core/hle/service/glue/ectx.h" | 8 | #include "core/hle/service/glue/ectx.h" |
| 9 | #include "core/hle/service/glue/glue.h" | 9 | #include "core/hle/service/glue/glue.h" |
| 10 | #include "core/hle/service/glue/notif.h" | 10 | #include "core/hle/service/glue/notif.h" |
| 11 | #include "core/hle/service/glue/time/manager.h" | ||
| 12 | #include "core/hle/service/glue/time/static.h" | ||
| 13 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | #include "core/hle/service/server_manager.h" | 14 | #include "core/hle/service/server_manager.h" |
| 12 | 15 | ||
| 13 | namespace Service::Glue { | 16 | namespace Service::Glue { |
| @@ -31,6 +34,22 @@ void LoopProcess(Core::System& system) { | |||
| 31 | // Notification Services for application | 34 | // Notification Services for application |
| 32 | server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); | 35 | server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); |
| 33 | 36 | ||
| 37 | // Time | ||
| 38 | auto time = std::make_shared<Time::TimeManager>(system); | ||
| 39 | |||
| 40 | server_manager->RegisterNamedService( | ||
| 41 | "time:u", | ||
| 42 | std::make_shared<Time::StaticService>( | ||
| 43 | system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, time, "time:u")); | ||
| 44 | server_manager->RegisterNamedService( | ||
| 45 | "time:a", | ||
| 46 | std::make_shared<Time::StaticService>( | ||
| 47 | system, Service::PSC::Time::StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, time, "time:a")); | ||
| 48 | server_manager->RegisterNamedService( | ||
| 49 | "time:r", | ||
| 50 | std::make_shared<Time::StaticService>( | ||
| 51 | system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, time, "time:r")); | ||
| 52 | |||
| 34 | ServerManager::RunServer(std::move(server_manager)); | 53 | ServerManager::RunServer(std::move(server_manager)); |
| 35 | } | 54 | } |
| 36 | 55 | ||
diff --git a/src/core/hle/service/glue/time/alarm_worker.cpp b/src/core/hle/service/glue/time/alarm_worker.cpp new file mode 100644 index 000000000..f549ed00a --- /dev/null +++ b/src/core/hle/service/glue/time/alarm_worker.cpp | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hle/kernel/svc.h" | ||
| 7 | #include "core/hle/service/glue/time/alarm_worker.h" | ||
| 8 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | namespace Service::Glue::Time { | ||
| 12 | |||
| 13 | AlarmWorker::AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource) | ||
| 14 | : m_system{system}, m_ctx{system, "Glue:AlarmWorker"}, m_steady_clock_resource{ | ||
| 15 | steady_clock_resource} {} | ||
| 16 | |||
| 17 | AlarmWorker::~AlarmWorker() { | ||
| 18 | m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); | ||
| 19 | |||
| 20 | m_ctx.CloseEvent(m_timer_event); | ||
| 21 | } | ||
| 22 | |||
| 23 | void AlarmWorker::Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m) { | ||
| 24 | m_time_m = std::move(time_m); | ||
| 25 | |||
| 26 | m_timer_event = m_ctx.CreateEvent("Glue:AlarmWorker:TimerEvent"); | ||
| 27 | m_timer_timing_event = Core::Timing::CreateEvent( | ||
| 28 | "Glue:AlarmWorker::AlarmTimer", | ||
| 29 | [this](s64 time, | ||
| 30 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 31 | m_timer_event->Signal(); | ||
| 32 | return std::nullopt; | ||
| 33 | }); | ||
| 34 | |||
| 35 | AttachToClosestAlarmEvent(); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, | ||
| 39 | s64& out_time) { | ||
| 40 | bool is_valid{}; | ||
| 41 | Service::PSC::Time::AlarmInfo alarm_info{}; | ||
| 42 | s64 closest_time{}; | ||
| 43 | |||
| 44 | auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time); | ||
| 45 | ASSERT(res == ResultSuccess); | ||
| 46 | |||
| 47 | if (is_valid) { | ||
| 48 | out_alarm_info = alarm_info; | ||
| 49 | out_time = closest_time; | ||
| 50 | } | ||
| 51 | |||
| 52 | return is_valid; | ||
| 53 | } | ||
| 54 | |||
| 55 | void AlarmWorker::OnPowerStateChanged() { | ||
| 56 | Service::PSC::Time::AlarmInfo closest_alarm_info{}; | ||
| 57 | s64 closest_time{}; | ||
| 58 | if (!GetClosestAlarmInfo(closest_alarm_info, closest_time)) { | ||
| 59 | m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); | ||
| 60 | m_timer_event->Clear(); | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | if (closest_alarm_info.alert_time <= closest_time) { | ||
| 65 | m_time_m->CheckAndSignalAlarms(); | ||
| 66 | } else { | ||
| 67 | auto next_time{closest_alarm_info.alert_time - closest_time}; | ||
| 68 | |||
| 69 | m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); | ||
| 70 | m_timer_event->Clear(); | ||
| 71 | |||
| 72 | m_system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds(next_time), | ||
| 73 | m_timer_timing_event); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | Result AlarmWorker::AttachToClosestAlarmEvent() { | ||
| 78 | m_time_m->GetClosestAlarmUpdatedEvent(&m_event); | ||
| 79 | R_SUCCEED(); | ||
| 80 | } | ||
| 81 | |||
| 82 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/alarm_worker.h b/src/core/hle/service/glue/time/alarm_worker.h new file mode 100644 index 000000000..f269cffdb --- /dev/null +++ b/src/core/hle/service/glue/time/alarm_worker.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 8 | #include "core/hle/service/kernel_helpers.h" | ||
| 9 | #include "core/hle/service/psc/time/common.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::PSC::Time { | ||
| 16 | class ServiceManager; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::Glue::Time { | ||
| 20 | class StandardSteadyClockResource; | ||
| 21 | |||
| 22 | class AlarmWorker { | ||
| 23 | public: | ||
| 24 | explicit AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource); | ||
| 25 | ~AlarmWorker(); | ||
| 26 | |||
| 27 | void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m); | ||
| 28 | |||
| 29 | Kernel::KEvent& GetEvent() { | ||
| 30 | return *m_event; | ||
| 31 | } | ||
| 32 | |||
| 33 | Kernel::KEvent& GetTimerEvent() { | ||
| 34 | return *m_timer_event; | ||
| 35 | } | ||
| 36 | |||
| 37 | void OnPowerStateChanged(); | ||
| 38 | |||
| 39 | private: | ||
| 40 | bool GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, s64& out_time); | ||
| 41 | Result AttachToClosestAlarmEvent(); | ||
| 42 | |||
| 43 | Core::System& m_system; | ||
| 44 | KernelHelpers::ServiceContext m_ctx; | ||
| 45 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; | ||
| 46 | |||
| 47 | Kernel::KEvent* m_event{}; | ||
| 48 | Kernel::KEvent* m_timer_event{}; | ||
| 49 | std::shared_ptr<Core::Timing::EventType> m_timer_timing_event; | ||
| 50 | StandardSteadyClockResource& m_steady_clock_resource; | ||
| 51 | }; | ||
| 52 | |||
| 53 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.cpp b/src/core/hle/service/glue/time/file_timestamp_worker.cpp new file mode 100644 index 000000000..5a6309549 --- /dev/null +++ b/src/core/hle/service/glue/time/file_timestamp_worker.cpp | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 5 | #include "core/hle/service/psc/time/common.h" | ||
| 6 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 7 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 8 | |||
| 9 | namespace Service::Glue::Time { | ||
| 10 | |||
| 11 | void FileTimestampWorker::SetFilesystemPosixTime() { | ||
| 12 | s64 time{}; | ||
| 13 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 14 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 15 | |||
| 16 | if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess && | ||
| 17 | m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) == | ||
| 18 | ResultSuccess) { | ||
| 19 | // TODO IFileSystemProxy::SetCurrentPosixTime | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.h b/src/core/hle/service/glue/time/file_timestamp_worker.h new file mode 100644 index 000000000..5f8b9b049 --- /dev/null +++ b/src/core/hle/service/glue/time/file_timestamp_worker.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Service::PSC::Time { | ||
| 11 | class SystemClock; | ||
| 12 | class TimeZoneService; | ||
| 13 | } // namespace Service::PSC::Time | ||
| 14 | |||
| 15 | namespace Service::Glue::Time { | ||
| 16 | |||
| 17 | class FileTimestampWorker { | ||
| 18 | public: | ||
| 19 | FileTimestampWorker() = default; | ||
| 20 | |||
| 21 | void SetFilesystemPosixTime(); | ||
| 22 | |||
| 23 | std::shared_ptr<Service::PSC::Time::SystemClock> m_system_clock{}; | ||
| 24 | std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone{}; | ||
| 25 | bool m_initialized{}; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp new file mode 100644 index 000000000..6423e5089 --- /dev/null +++ b/src/core/hle/service/glue/time/manager.cpp | |||
| @@ -0,0 +1,277 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | |||
| 9 | #include "common/settings.h" | ||
| 10 | #include "common/time_zone.h" | ||
| 11 | #include "core/file_sys/vfs.h" | ||
| 12 | #include "core/hle/kernel/svc.h" | ||
| 13 | #include "core/hle/service/glue/time/manager.h" | ||
| 14 | #include "core/hle/service/glue/time/time_zone_binary.h" | ||
| 15 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 16 | #include "core/hle/service/psc/time/static.h" | ||
| 17 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 18 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 19 | #include "core/hle/service/set/system_settings_server.h" | ||
| 20 | #include "core/hle/service/sm/sm.h" | ||
| 21 | |||
| 22 | namespace Service::Glue::Time { | ||
| 23 | namespace { | ||
| 24 | |||
| 25 | template <typename T> | ||
| 26 | T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, | ||
| 27 | const char* category, const char* name) { | ||
| 28 | std::vector<u8> interval_buf; | ||
| 29 | auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); | ||
| 30 | ASSERT(res == ResultSuccess); | ||
| 31 | |||
| 32 | T v{}; | ||
| 33 | std::memcpy(&v, interval_buf.data(), sizeof(T)); | ||
| 34 | return v; | ||
| 35 | } | ||
| 36 | |||
| 37 | s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) { | ||
| 38 | constexpr auto is_leap = [](s32 year) -> bool { | ||
| 39 | return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)); | ||
| 40 | }; | ||
| 41 | constexpr std::array<s32, 12> MonthStartDayOfYear{ | ||
| 42 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, | ||
| 43 | }; | ||
| 44 | |||
| 45 | s16 month_s16{calendar.month}; | ||
| 46 | s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) + | ||
| 47 | ((month_s16 * 43) >> 9))}; | ||
| 48 | s8 month_index{static_cast<s8>(calendar.month - 12 * month)}; | ||
| 49 | if (month_index == 0) { | ||
| 50 | month_index = 12; | ||
| 51 | } | ||
| 52 | s32 year{(month + calendar.year) - !month_index}; | ||
| 53 | s32 v8{year >= 0 ? year : year + 3}; | ||
| 54 | |||
| 55 | s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1]; | ||
| 56 | days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365; | ||
| 57 | |||
| 58 | if (month_index <= 2 && is_leap(year)) { | ||
| 59 | days_since_epoch--; | ||
| 60 | } | ||
| 61 | auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll + | ||
| 62 | calendar.second}; | ||
| 63 | return epoch_s - 62135683200ll; | ||
| 64 | } | ||
| 65 | |||
| 66 | s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) { | ||
| 67 | Service::PSC::Time::CalendarTime calendar{ | ||
| 68 | .year = GetSettingsItemValue<s16>(set_sys, "time", "standard_user_clock_initial_year"), | ||
| 69 | .month = 1, | ||
| 70 | .day = 1, | ||
| 71 | .hour = 0, | ||
| 72 | .minute = 0, | ||
| 73 | .second = 0, | ||
| 74 | }; | ||
| 75 | return CalendarTimeToEpoch(calendar); | ||
| 76 | } | ||
| 77 | |||
| 78 | Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationName& in_name) { | ||
| 79 | auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); | ||
| 80 | |||
| 81 | Service::PSC::Time::LocationName configured_name{}; | ||
| 82 | std::memcpy(configured_name.name.data(), configured_zone.data(), | ||
| 83 | std::min(configured_name.name.size(), configured_zone.size())); | ||
| 84 | |||
| 85 | if (!IsTimeZoneBinaryValid(configured_name)) { | ||
| 86 | configured_zone = Common::TimeZone::FindSystemTimeZone(); | ||
| 87 | configured_name = {}; | ||
| 88 | std::memcpy(configured_name.name.data(), configured_zone.data(), | ||
| 89 | std::min(configured_name.name.size(), configured_zone.size())); | ||
| 90 | } | ||
| 91 | |||
| 92 | ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!", | ||
| 93 | configured_name.name.data()); | ||
| 94 | |||
| 95 | return configured_name; | ||
| 96 | } | ||
| 97 | |||
| 98 | } // namespace | ||
| 99 | |||
| 100 | TimeManager::TimeManager(Core::System& system) | ||
| 101 | : m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource, | ||
| 102 | m_file_timestamp_worker} { | ||
| 103 | m_time_m = | ||
| 104 | system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); | ||
| 105 | |||
| 106 | auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm); | ||
| 107 | ASSERT(res == ResultSuccess); | ||
| 108 | |||
| 109 | m_set_sys = | ||
| 110 | system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 111 | |||
| 112 | res = MountTimeZoneBinary(system); | ||
| 113 | ASSERT(res == ResultSuccess); | ||
| 114 | |||
| 115 | m_worker.Initialize(m_time_sm, m_set_sys); | ||
| 116 | |||
| 117 | res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock); | ||
| 118 | ASSERT(res == ResultSuccess); | ||
| 119 | |||
| 120 | res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone); | ||
| 121 | ASSERT(res == ResultSuccess); | ||
| 122 | |||
| 123 | res = SetupStandardSteadyClockCore(); | ||
| 124 | ASSERT(res == ResultSuccess); | ||
| 125 | |||
| 126 | Service::PSC::Time::SystemClockContext user_clock_context{}; | ||
| 127 | res = m_set_sys->GetUserSystemClockContext(user_clock_context); | ||
| 128 | ASSERT(res == ResultSuccess); | ||
| 129 | |||
| 130 | // TODO the local clock should initialise with this epoch time, and be updated somewhere else on | ||
| 131 | // first boot to update it, but I haven't been able to find that point (likely via ntc's auto | ||
| 132 | // correct as it's defaulted to be enabled). So to get a time that isn't stuck in the past for | ||
| 133 | // first boot, grab the current real seconds. | ||
| 134 | auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)}; | ||
| 135 | if (user_clock_context == Service::PSC::Time::SystemClockContext{}) { | ||
| 136 | m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time); | ||
| 137 | } | ||
| 138 | |||
| 139 | res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time); | ||
| 140 | ASSERT(res == ResultSuccess); | ||
| 141 | |||
| 142 | Service::PSC::Time::SystemClockContext network_clock_context{}; | ||
| 143 | res = m_set_sys->GetNetworkSystemClockContext(network_clock_context); | ||
| 144 | ASSERT(res == ResultSuccess); | ||
| 145 | |||
| 146 | auto network_accuracy_m{GetSettingsItemValue<s32>( | ||
| 147 | m_set_sys, "time", "standard_network_clock_sufficient_accuracy_minutes")}; | ||
| 148 | auto one_minute_ns{ | ||
| 149 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; | ||
| 150 | s64 network_accuracy_ns{network_accuracy_m * one_minute_ns}; | ||
| 151 | |||
| 152 | res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns); | ||
| 153 | ASSERT(res == ResultSuccess); | ||
| 154 | |||
| 155 | bool is_automatic_correction_enabled{}; | ||
| 156 | res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(is_automatic_correction_enabled); | ||
| 157 | ASSERT(res == ResultSuccess); | ||
| 158 | |||
| 159 | Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{}; | ||
| 160 | res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 161 | automatic_correction_time_point); | ||
| 162 | ASSERT(res == ResultSuccess); | ||
| 163 | |||
| 164 | res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point, | ||
| 165 | is_automatic_correction_enabled); | ||
| 166 | ASSERT(res == ResultSuccess); | ||
| 167 | |||
| 168 | res = m_time_m->SetupEphemeralNetworkSystemClockCore(); | ||
| 169 | ASSERT(res == ResultSuccess); | ||
| 170 | |||
| 171 | res = SetupTimeZoneServiceCore(); | ||
| 172 | ASSERT(res == ResultSuccess); | ||
| 173 | |||
| 174 | s64 rtc_time_s{}; | ||
| 175 | res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s); | ||
| 176 | ASSERT(res == ResultSuccess); | ||
| 177 | |||
| 178 | // TODO system report "launch" | ||
| 179 | // "rtc_reset" = m_steady_clock_resource.m_rtc_reset | ||
| 180 | // "rtc_value" = rtc_time_s | ||
| 181 | |||
| 182 | m_worker.StartThread(); | ||
| 183 | |||
| 184 | m_file_timestamp_worker.m_initialized = true; | ||
| 185 | |||
| 186 | s64 system_clock_time{}; | ||
| 187 | if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) == | ||
| 188 | ResultSuccess) { | ||
| 189 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 190 | Service::PSC::Time::CalendarAdditionalInfo calendar_additional{}; | ||
| 191 | if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule( | ||
| 192 | calendar_time, calendar_additional, system_clock_time) == ResultSuccess) { | ||
| 193 | // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time, | ||
| 194 | // calendar_additional.ut_offset) | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | Result TimeManager::SetupStandardSteadyClockCore() { | ||
| 200 | Common::UUID external_clock_source_id{}; | ||
| 201 | auto res = m_set_sys->GetExternalSteadyClockSourceId(external_clock_source_id); | ||
| 202 | ASSERT(res == ResultSuccess); | ||
| 203 | |||
| 204 | s64 external_steady_clock_internal_offset_s{}; | ||
| 205 | res = m_set_sys->GetExternalSteadyClockInternalOffset(external_steady_clock_internal_offset_s); | ||
| 206 | ASSERT(res == ResultSuccess); | ||
| 207 | |||
| 208 | auto one_second_ns{ | ||
| 209 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 210 | s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s * | ||
| 211 | one_second_ns}; | ||
| 212 | |||
| 213 | s32 standard_steady_clock_test_offset_m{ | ||
| 214 | GetSettingsItemValue<s32>(m_set_sys, "time", "standard_steady_clock_test_offset_minutes")}; | ||
| 215 | auto one_minute_ns{ | ||
| 216 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; | ||
| 217 | s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns}; | ||
| 218 | |||
| 219 | auto reset_detected = m_steady_clock_resource.GetResetDetected(); | ||
| 220 | if (reset_detected) { | ||
| 221 | external_clock_source_id = {}; | ||
| 222 | } | ||
| 223 | |||
| 224 | Common::UUID clock_source_id{}; | ||
| 225 | m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id); | ||
| 226 | |||
| 227 | if (clock_source_id != external_clock_source_id) { | ||
| 228 | m_set_sys->SetExternalSteadyClockSourceId(clock_source_id); | ||
| 229 | } | ||
| 230 | |||
| 231 | res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(), | ||
| 232 | external_steady_clock_internal_offset_ns, | ||
| 233 | standard_steady_clock_test_offset_ns, | ||
| 234 | reset_detected); | ||
| 235 | ASSERT(res == ResultSuccess); | ||
| 236 | R_SUCCEED(); | ||
| 237 | } | ||
| 238 | |||
| 239 | Result TimeManager::SetupTimeZoneServiceCore() { | ||
| 240 | Service::PSC::Time::LocationName name{}; | ||
| 241 | auto res = m_set_sys->GetDeviceTimeZoneLocationName(name); | ||
| 242 | ASSERT(res == ResultSuccess); | ||
| 243 | |||
| 244 | auto configured_zone = GetTimeZoneString(name); | ||
| 245 | |||
| 246 | if (configured_zone.name != name.name) { | ||
| 247 | m_set_sys->SetDeviceTimeZoneLocationName(configured_zone); | ||
| 248 | name = configured_zone; | ||
| 249 | |||
| 250 | std::shared_ptr<Service::PSC::Time::SystemClock> local_clock; | ||
| 251 | m_time_sm->GetStandardLocalSystemClock(local_clock); | ||
| 252 | Service::PSC::Time::SystemClockContext context{}; | ||
| 253 | local_clock->GetSystemClockContext(context); | ||
| 254 | m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point); | ||
| 255 | } | ||
| 256 | |||
| 257 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 258 | res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(time_point); | ||
| 259 | ASSERT(res == ResultSuccess); | ||
| 260 | |||
| 261 | auto location_count = GetTimeZoneCount(); | ||
| 262 | Service::PSC::Time::RuleVersion rule_version{}; | ||
| 263 | GetTimeZoneVersion(rule_version); | ||
| 264 | |||
| 265 | std::span<const u8> rule_buffer{}; | ||
| 266 | size_t rule_size{}; | ||
| 267 | res = GetTimeZoneRule(rule_buffer, rule_size, name); | ||
| 268 | ASSERT(res == ResultSuccess); | ||
| 269 | |||
| 270 | res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count, | ||
| 271 | rule_buffer); | ||
| 272 | ASSERT(res == ResultSuccess); | ||
| 273 | |||
| 274 | R_SUCCEED(); | ||
| 275 | } | ||
| 276 | |||
| 277 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/manager.h b/src/core/hle/service/glue/time/manager.h new file mode 100644 index 000000000..a46ec6364 --- /dev/null +++ b/src/core/hle/service/glue/time/manager.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <functional> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/vfs_types.h" | ||
| 11 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 12 | #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||
| 13 | #include "core/hle/service/glue/time/worker.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::PSC::Time { | ||
| 21 | class ServiceManager; | ||
| 22 | class StaticService; | ||
| 23 | } // namespace Service::PSC::Time | ||
| 24 | |||
| 25 | namespace Service::Glue::Time { | ||
| 26 | class TimeManager { | ||
| 27 | public: | ||
| 28 | explicit TimeManager(Core::System& system); | ||
| 29 | |||
| 30 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 31 | |||
| 32 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m{}; | ||
| 33 | std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{}; | ||
| 34 | StandardSteadyClockResource m_steady_clock_resource; | ||
| 35 | FileTimestampWorker m_file_timestamp_worker; | ||
| 36 | TimeWorker m_worker; | ||
| 37 | |||
| 38 | private: | ||
| 39 | Result SetupStandardSteadyClockCore(); | ||
| 40 | Result SetupTimeZoneServiceCore(); | ||
| 41 | }; | ||
| 42 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.cpp b/src/core/hle/service/glue/time/pm_state_change_handler.cpp new file mode 100644 index 000000000..7470fb225 --- /dev/null +++ b/src/core/hle/service/glue/time/pm_state_change_handler.cpp | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/glue/time/pm_state_change_handler.h" | ||
| 5 | |||
| 6 | namespace Service::Glue::Time { | ||
| 7 | |||
| 8 | PmStateChangeHandler::PmStateChangeHandler(AlarmWorker& alarm_worker) | ||
| 9 | : m_alarm_worker{alarm_worker} { | ||
| 10 | // TODO Initialize IPmModule, dependent on Rtc and Fs | ||
| 11 | } | ||
| 12 | |||
| 13 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.h b/src/core/hle/service/glue/time/pm_state_change_handler.h new file mode 100644 index 000000000..27d9f7872 --- /dev/null +++ b/src/core/hle/service/glue/time/pm_state_change_handler.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | namespace Service::Glue::Time { | ||
| 9 | class AlarmWorker; | ||
| 10 | |||
| 11 | class PmStateChangeHandler { | ||
| 12 | public: | ||
| 13 | explicit PmStateChangeHandler(AlarmWorker& alarm_worker); | ||
| 14 | |||
| 15 | AlarmWorker& m_alarm_worker; | ||
| 16 | s32 m_priority{}; | ||
| 17 | }; | ||
| 18 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp new file mode 100644 index 000000000..5ebaa33e0 --- /dev/null +++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "common/settings.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/kernel/svc.h" | ||
| 10 | #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||
| 11 | #include "core/hle/service/psc/time/errors.h" | ||
| 12 | |||
| 13 | namespace Service::Glue::Time { | ||
| 14 | namespace { | ||
| 15 | [[maybe_unused]] constexpr u32 Max77620PmicSession = 0x3A000001; | ||
| 16 | [[maybe_unused]] constexpr u32 Max77620RtcSession = 0x3B000001; | ||
| 17 | |||
| 18 | Result GetTimeInSeconds(Core::System& system, s64& out_time_s) { | ||
| 19 | out_time_s = std::chrono::duration_cast<std::chrono::seconds>( | ||
| 20 | std::chrono::system_clock::now().time_since_epoch()) | ||
| 21 | .count(); | ||
| 22 | |||
| 23 | if (Settings::values.custom_rtc_enabled) { | ||
| 24 | out_time_s += Settings::values.custom_rtc_offset.GetValue(); | ||
| 25 | } | ||
| 26 | R_SUCCEED(); | ||
| 27 | } | ||
| 28 | } // namespace | ||
| 29 | |||
| 30 | StandardSteadyClockResource::StandardSteadyClockResource(Core::System& system) : m_system{system} {} | ||
| 31 | |||
| 32 | void StandardSteadyClockResource::Initialize(Common::UUID* out_source_id, | ||
| 33 | Common::UUID* external_source_id) { | ||
| 34 | constexpr size_t NUM_TRIES{20}; | ||
| 35 | |||
| 36 | size_t i{0}; | ||
| 37 | Result res{ResultSuccess}; | ||
| 38 | for (; i < NUM_TRIES; i++) { | ||
| 39 | res = SetCurrentTime(); | ||
| 40 | if (res == ResultSuccess) { | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
| 44 | std::chrono::milliseconds(1)) | ||
| 45 | .count()); | ||
| 46 | } | ||
| 47 | |||
| 48 | if (i < NUM_TRIES) { | ||
| 49 | m_set_time_result = ResultSuccess; | ||
| 50 | if (*external_source_id != Service::PSC::Time::ClockSourceId{}) { | ||
| 51 | m_clock_source_id = *external_source_id; | ||
| 52 | } else { | ||
| 53 | m_clock_source_id = Common::UUID::MakeRandom(); | ||
| 54 | } | ||
| 55 | } else { | ||
| 56 | m_set_time_result = res; | ||
| 57 | auto ticks{m_system.CoreTiming().GetClockTicks()}; | ||
| 58 | m_time = -Service::PSC::Time::ConvertToTimeSpan(ticks).count(); | ||
| 59 | m_clock_source_id = Common::UUID::MakeRandom(); | ||
| 60 | } | ||
| 61 | |||
| 62 | if (out_source_id) { | ||
| 63 | *out_source_id = m_clock_source_id; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | bool StandardSteadyClockResource::GetResetDetected() { | ||
| 68 | // TODO: | ||
| 69 | // call Rtc::GetRtcResetDetected(Max77620RtcSession) | ||
| 70 | // if detected: | ||
| 71 | // SetSys::SetExternalSteadyClockSourceId(invalid_id) | ||
| 72 | // Rtc::ClearRtcResetDetected(Max77620RtcSession) | ||
| 73 | // set m_rtc_reset to result | ||
| 74 | // Instead, only set reset to true if we're booting for the first time. | ||
| 75 | m_rtc_reset = false; | ||
| 76 | return m_rtc_reset; | ||
| 77 | } | ||
| 78 | |||
| 79 | Result StandardSteadyClockResource::SetCurrentTime() { | ||
| 80 | auto start_tick{m_system.CoreTiming().GetClockTicks()}; | ||
| 81 | |||
| 82 | s64 rtc_time_s{}; | ||
| 83 | // TODO R_TRY(Rtc::GetTimeInSeconds(rtc_time_s, Max77620RtcSession)) | ||
| 84 | R_TRY(GetTimeInSeconds(m_system, rtc_time_s)); | ||
| 85 | |||
| 86 | auto end_tick{m_system.CoreTiming().GetClockTicks()}; | ||
| 87 | auto diff{Service::PSC::Time::ConvertToTimeSpan(end_tick - start_tick)}; | ||
| 88 | // Why is this here? | ||
| 89 | R_UNLESS(diff < std::chrono::milliseconds(101), Service::PSC::Time::ResultRtcTimeout); | ||
| 90 | |||
| 91 | auto one_second_ns{ | ||
| 92 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 93 | s64 boot_time{rtc_time_s * one_second_ns - | ||
| 94 | Service::PSC::Time::ConvertToTimeSpan(end_tick).count()}; | ||
| 95 | |||
| 96 | std::scoped_lock l{m_mutex}; | ||
| 97 | m_time = boot_time; | ||
| 98 | R_SUCCEED(); | ||
| 99 | } | ||
| 100 | |||
| 101 | Result StandardSteadyClockResource::GetRtcTimeInSeconds(s64& out_time) { | ||
| 102 | // TODO | ||
| 103 | // R_TRY(Rtc::GetTimeInSeconds(time_s, Max77620RtcSession) | ||
| 104 | R_RETURN(GetTimeInSeconds(m_system, out_time)); | ||
| 105 | } | ||
| 106 | |||
| 107 | void StandardSteadyClockResource::UpdateTime() { | ||
| 108 | constexpr size_t NUM_TRIES{3}; | ||
| 109 | |||
| 110 | size_t i{0}; | ||
| 111 | Result res{ResultSuccess}; | ||
| 112 | for (; i < NUM_TRIES; i++) { | ||
| 113 | res = SetCurrentTime(); | ||
| 114 | if (res == ResultSuccess) { | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
| 118 | std::chrono::milliseconds(1)) | ||
| 119 | .count()); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.h b/src/core/hle/service/glue/time/standard_steady_clock_resource.h new file mode 100644 index 000000000..978d6b63b --- /dev/null +++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Glue::Time { | ||
| 17 | class StandardSteadyClockResource { | ||
| 18 | public: | ||
| 19 | StandardSteadyClockResource(Core::System& system); | ||
| 20 | |||
| 21 | void Initialize(Common::UUID* out_source_id, Common::UUID* external_source_id); | ||
| 22 | |||
| 23 | s64 GetTime() const { | ||
| 24 | return m_time; | ||
| 25 | } | ||
| 26 | |||
| 27 | bool GetResetDetected(); | ||
| 28 | Result SetCurrentTime(); | ||
| 29 | Result GetRtcTimeInSeconds(s64& out_time); | ||
| 30 | void UpdateTime(); | ||
| 31 | |||
| 32 | private: | ||
| 33 | Core::System& m_system; | ||
| 34 | |||
| 35 | std::mutex m_mutex; | ||
| 36 | Service::PSC::Time::ClockSourceId m_clock_source_id{}; | ||
| 37 | s64 m_time{}; | ||
| 38 | Result m_set_time_result; | ||
| 39 | bool m_rtc_reset; | ||
| 40 | }; | ||
| 41 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp new file mode 100644 index 000000000..63b7d91da --- /dev/null +++ b/src/core/hle/service/glue/time/static.cpp | |||
| @@ -0,0 +1,448 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 8 | #include "core/hle/kernel/svc.h" | ||
| 9 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 10 | #include "core/hle/service/glue/time/static.h" | ||
| 11 | #include "core/hle/service/psc/time/errors.h" | ||
| 12 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 13 | #include "core/hle/service/psc/time/static.h" | ||
| 14 | #include "core/hle/service/psc/time/steady_clock.h" | ||
| 15 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 16 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 17 | #include "core/hle/service/set/system_settings_server.h" | ||
| 18 | #include "core/hle/service/sm/sm.h" | ||
| 19 | |||
| 20 | namespace Service::Glue::Time { | ||
| 21 | namespace { | ||
| 22 | template <typename T> | ||
| 23 | T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, | ||
| 24 | const char* category, const char* name) { | ||
| 25 | std::vector<u8> interval_buf; | ||
| 26 | auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); | ||
| 27 | ASSERT(res == ResultSuccess); | ||
| 28 | |||
| 29 | T v{}; | ||
| 30 | std::memcpy(&v, interval_buf.data(), sizeof(T)); | ||
| 31 | return v; | ||
| 32 | } | ||
| 33 | } // namespace | ||
| 34 | |||
| 35 | StaticService::StaticService(Core::System& system_, | ||
| 36 | Service::PSC::Time::StaticServiceSetupInfo setup_info, | ||
| 37 | std::shared_ptr<TimeManager> time, const char* name) | ||
| 38 | : ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m}, | ||
| 39 | m_setup_info{setup_info}, m_time_sm{time->m_time_sm}, | ||
| 40 | m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{ | ||
| 41 | time->m_steady_clock_resource} { | ||
| 42 | // clang-format off | ||
| 43 | static const FunctionInfo functions[] = { | ||
| 44 | {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | ||
| 45 | {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | ||
| 46 | {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, | ||
| 47 | {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, | ||
| 48 | {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | ||
| 49 | {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, | ||
| 50 | {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, | ||
| 51 | {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, | ||
| 52 | {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, | ||
| 53 | {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 54 | {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 55 | {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, | ||
| 56 | {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, | ||
| 57 | {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 58 | {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, | ||
| 59 | {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, | ||
| 60 | {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, | ||
| 61 | {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, | ||
| 62 | {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, | ||
| 63 | }; | ||
| 64 | // clang-format on | ||
| 65 | |||
| 66 | RegisterHandlers(functions); | ||
| 67 | |||
| 68 | m_set_sys = | ||
| 69 | m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 70 | |||
| 71 | if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock && | ||
| 72 | !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location && | ||
| 73 | !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { | ||
| 74 | m_time_m->GetStaticServiceAsAdmin(m_wrapped_service); | ||
| 75 | } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && | ||
| 76 | !m_setup_info.can_write_network_clock && | ||
| 77 | !m_setup_info.can_write_timezone_device_location && | ||
| 78 | !m_setup_info.can_write_steady_clock && | ||
| 79 | !m_setup_info.can_write_uninitialized_clock) { | ||
| 80 | m_time_m->GetStaticServiceAsUser(m_wrapped_service); | ||
| 81 | } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && | ||
| 82 | !m_setup_info.can_write_network_clock && | ||
| 83 | !m_setup_info.can_write_timezone_device_location && | ||
| 84 | m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { | ||
| 85 | m_time_m->GetStaticServiceAsRepair(m_wrapped_service); | ||
| 86 | } else { | ||
| 87 | UNREACHABLE(); | ||
| 88 | } | ||
| 89 | |||
| 90 | auto res = m_wrapped_service->GetTimeZoneService(m_time_zone); | ||
| 91 | ASSERT(res == ResultSuccess); | ||
| 92 | } | ||
| 93 | |||
| 94 | void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) { | ||
| 95 | LOG_DEBUG(Service_Time, "called."); | ||
| 96 | |||
| 97 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 98 | auto res = GetStandardUserSystemClock(service); | ||
| 99 | |||
| 100 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 101 | rb.Push(res); | ||
| 102 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 103 | } | ||
| 104 | |||
| 105 | void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) { | ||
| 106 | LOG_DEBUG(Service_Time, "called."); | ||
| 107 | |||
| 108 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 109 | auto res = GetStandardNetworkSystemClock(service); | ||
| 110 | |||
| 111 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 112 | rb.Push(res); | ||
| 113 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 114 | } | ||
| 115 | |||
| 116 | void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) { | ||
| 117 | LOG_DEBUG(Service_Time, "called."); | ||
| 118 | |||
| 119 | std::shared_ptr<Service::PSC::Time::SteadyClock> service{}; | ||
| 120 | auto res = GetStandardSteadyClock(service); | ||
| 121 | |||
| 122 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 123 | rb.Push(res); | ||
| 124 | rb.PushIpcInterface(std::move(service)); | ||
| 125 | } | ||
| 126 | |||
| 127 | void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) { | ||
| 128 | LOG_DEBUG(Service_Time, "called."); | ||
| 129 | |||
| 130 | std::shared_ptr<TimeZoneService> service{}; | ||
| 131 | auto res = GetTimeZoneService(service); | ||
| 132 | |||
| 133 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 134 | rb.Push(res); | ||
| 135 | rb.PushIpcInterface(std::move(service)); | ||
| 136 | } | ||
| 137 | |||
| 138 | void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) { | ||
| 139 | LOG_DEBUG(Service_Time, "called."); | ||
| 140 | |||
| 141 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 142 | auto res = GetStandardLocalSystemClock(service); | ||
| 143 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 145 | rb.Push(res); | ||
| 146 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 147 | } | ||
| 148 | |||
| 149 | void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) { | ||
| 150 | LOG_DEBUG(Service_Time, "called."); | ||
| 151 | |||
| 152 | std::shared_ptr<Service::PSC::Time::SystemClock> service{}; | ||
| 153 | auto res = GetEphemeralNetworkSystemClock(service); | ||
| 154 | |||
| 155 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 156 | rb.Push(res); | ||
| 157 | rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); | ||
| 158 | } | ||
| 159 | |||
| 160 | void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) { | ||
| 161 | LOG_DEBUG(Service_Time, "called."); | ||
| 162 | |||
| 163 | Kernel::KSharedMemory* shared_memory{}; | ||
| 164 | auto res = GetSharedMemoryNativeHandle(&shared_memory); | ||
| 165 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 167 | rb.Push(res); | ||
| 168 | rb.PushCopyObjects(shared_memory); | ||
| 169 | } | ||
| 170 | |||
| 171 | void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) { | ||
| 172 | LOG_DEBUG(Service_Time, "called."); | ||
| 173 | |||
| 174 | IPC::RequestParser rp{ctx}; | ||
| 175 | auto offset_ns{rp.Pop<s64>()}; | ||
| 176 | |||
| 177 | auto res = SetStandardSteadyClockInternalOffset(offset_ns); | ||
| 178 | |||
| 179 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 180 | rb.Push(res); | ||
| 181 | } | ||
| 182 | |||
| 183 | void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) { | ||
| 184 | LOG_DEBUG(Service_Time, "called."); | ||
| 185 | |||
| 186 | s64 rtc_value{}; | ||
| 187 | auto res = GetStandardSteadyClockRtcValue(rtc_value); | ||
| 188 | |||
| 189 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 190 | rb.Push(res); | ||
| 191 | rb.Push(rtc_value); | ||
| 192 | } | ||
| 193 | |||
| 194 | void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 195 | HLERequestContext& ctx) { | ||
| 196 | LOG_DEBUG(Service_Time, "called."); | ||
| 197 | |||
| 198 | bool is_enabled{}; | ||
| 199 | auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled); | ||
| 200 | |||
| 201 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 202 | rb.Push(res); | ||
| 203 | rb.Push<bool>(is_enabled); | ||
| 204 | } | ||
| 205 | |||
| 206 | void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 207 | HLERequestContext& ctx) { | ||
| 208 | LOG_DEBUG(Service_Time, "called."); | ||
| 209 | |||
| 210 | IPC::RequestParser rp{ctx}; | ||
| 211 | auto automatic_correction{rp.Pop<bool>()}; | ||
| 212 | |||
| 213 | auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction); | ||
| 214 | |||
| 215 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 216 | rb.Push(res); | ||
| 217 | } | ||
| 218 | |||
| 219 | void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) { | ||
| 220 | LOG_DEBUG(Service_Time, "called."); | ||
| 221 | |||
| 222 | s32 initial_year{}; | ||
| 223 | auto res = GetStandardUserSystemClockInitialYear(initial_year); | ||
| 224 | |||
| 225 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 226 | rb.Push(res); | ||
| 227 | rb.Push(initial_year); | ||
| 228 | } | ||
| 229 | |||
| 230 | void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { | ||
| 231 | LOG_DEBUG(Service_Time, "called."); | ||
| 232 | |||
| 233 | bool is_sufficient{}; | ||
| 234 | auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 237 | rb.Push(res); | ||
| 238 | rb.Push<bool>(is_sufficient); | ||
| 239 | } | ||
| 240 | |||
| 241 | void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 242 | HLERequestContext& ctx) { | ||
| 243 | LOG_DEBUG(Service_Time, "called."); | ||
| 244 | |||
| 245 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 246 | auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 247 | |||
| 248 | IPC::ResponseBuilder rb{ctx, | ||
| 249 | 2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)}; | ||
| 250 | rb.Push(res); | ||
| 251 | rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); | ||
| 252 | } | ||
| 253 | |||
| 254 | void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { | ||
| 255 | LOG_DEBUG(Service_Time, "called."); | ||
| 256 | |||
| 257 | IPC::RequestParser rp{ctx}; | ||
| 258 | auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; | ||
| 259 | |||
| 260 | s64 time{}; | ||
| 261 | auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context); | ||
| 262 | |||
| 263 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 264 | rb.Push(res); | ||
| 265 | rb.Push<s64>(time); | ||
| 266 | } | ||
| 267 | |||
| 268 | void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { | ||
| 269 | LOG_DEBUG(Service_Time, "called."); | ||
| 270 | |||
| 271 | IPC::RequestParser rp{ctx}; | ||
| 272 | auto type{rp.PopEnum<Service::PSC::Time::TimeType>()}; | ||
| 273 | |||
| 274 | Service::PSC::Time::ClockSnapshot snapshot{}; | ||
| 275 | auto res = GetClockSnapshot(snapshot, type); | ||
| 276 | |||
| 277 | ctx.WriteBuffer(snapshot); | ||
| 278 | |||
| 279 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 280 | rb.Push(res); | ||
| 281 | } | ||
| 282 | |||
| 283 | void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { | ||
| 284 | LOG_DEBUG(Service_Time, "called."); | ||
| 285 | |||
| 286 | IPC::RequestParser rp{ctx}; | ||
| 287 | auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()}; | ||
| 288 | [[maybe_unused]] auto alignment{rp.Pop<u32>()}; | ||
| 289 | auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; | ||
| 290 | auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; | ||
| 291 | |||
| 292 | Service::PSC::Time::ClockSnapshot snapshot{}; | ||
| 293 | auto res = | ||
| 294 | GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type); | ||
| 295 | |||
| 296 | ctx.WriteBuffer(snapshot); | ||
| 297 | |||
| 298 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 299 | rb.Push(res); | ||
| 300 | } | ||
| 301 | |||
| 302 | void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( | ||
| 303 | HLERequestContext& ctx) { | ||
| 304 | LOG_DEBUG(Service_Time, "called."); | ||
| 305 | |||
| 306 | Service::PSC::Time::ClockSnapshot a{}; | ||
| 307 | Service::PSC::Time::ClockSnapshot b{}; | ||
| 308 | |||
| 309 | auto a_buffer{ctx.ReadBuffer(0)}; | ||
| 310 | auto b_buffer{ctx.ReadBuffer(1)}; | ||
| 311 | |||
| 312 | std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 313 | std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 314 | |||
| 315 | s64 difference{}; | ||
| 316 | auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b); | ||
| 317 | |||
| 318 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 319 | rb.Push(res); | ||
| 320 | rb.Push(difference); | ||
| 321 | } | ||
| 322 | |||
| 323 | void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { | ||
| 324 | LOG_DEBUG(Service_Time, "called."); | ||
| 325 | |||
| 326 | Service::PSC::Time::ClockSnapshot a{}; | ||
| 327 | Service::PSC::Time::ClockSnapshot b{}; | ||
| 328 | |||
| 329 | auto a_buffer{ctx.ReadBuffer(0)}; | ||
| 330 | auto b_buffer{ctx.ReadBuffer(1)}; | ||
| 331 | |||
| 332 | std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 333 | std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); | ||
| 334 | |||
| 335 | s64 time{}; | ||
| 336 | auto res = CalculateSpanBetween(time, a, b); | ||
| 337 | |||
| 338 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 339 | rb.Push(res); | ||
| 340 | rb.Push(time); | ||
| 341 | } | ||
| 342 | |||
| 343 | // =============================== Implementations =========================== | ||
| 344 | |||
| 345 | Result StaticService::GetStandardUserSystemClock( | ||
| 346 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 347 | R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service)); | ||
| 348 | } | ||
| 349 | |||
| 350 | Result StaticService::GetStandardNetworkSystemClock( | ||
| 351 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 352 | R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service)); | ||
| 353 | } | ||
| 354 | |||
| 355 | Result StaticService::GetStandardSteadyClock( | ||
| 356 | std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) { | ||
| 357 | R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service)); | ||
| 358 | } | ||
| 359 | |||
| 360 | Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) { | ||
| 361 | out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker, | ||
| 362 | m_setup_info.can_write_timezone_device_location, | ||
| 363 | m_time_zone); | ||
| 364 | R_SUCCEED(); | ||
| 365 | } | ||
| 366 | |||
| 367 | Result StaticService::GetStandardLocalSystemClock( | ||
| 368 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 369 | R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service)); | ||
| 370 | } | ||
| 371 | |||
| 372 | Result StaticService::GetEphemeralNetworkSystemClock( | ||
| 373 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { | ||
| 374 | R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service)); | ||
| 375 | } | ||
| 376 | |||
| 377 | Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) { | ||
| 378 | R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory)); | ||
| 379 | } | ||
| 380 | |||
| 381 | Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) { | ||
| 382 | R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied); | ||
| 383 | |||
| 384 | R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset( | ||
| 385 | offset_ns / | ||
| 386 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count())); | ||
| 387 | } | ||
| 388 | |||
| 389 | Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) { | ||
| 390 | R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value)); | ||
| 391 | } | ||
| 392 | |||
| 393 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 394 | bool& out_automatic_correction) { | ||
| 395 | R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 396 | out_automatic_correction)); | ||
| 397 | } | ||
| 398 | |||
| 399 | Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 400 | bool automatic_correction) { | ||
| 401 | R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 402 | automatic_correction)); | ||
| 403 | } | ||
| 404 | |||
| 405 | Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) { | ||
| 406 | out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year"); | ||
| 407 | R_SUCCEED(); | ||
| 408 | } | ||
| 409 | |||
| 410 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { | ||
| 411 | R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); | ||
| 412 | } | ||
| 413 | |||
| 414 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 415 | Service::PSC::Time::SteadyClockTimePoint& out_time_point) { | ||
| 416 | R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 417 | out_time_point)); | ||
| 418 | } | ||
| 419 | |||
| 420 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( | ||
| 421 | s64& out_time, Service::PSC::Time::SystemClockContext& context) { | ||
| 422 | R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); | ||
| 423 | } | ||
| 424 | |||
| 425 | Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 426 | Service::PSC::Time::TimeType type) { | ||
| 427 | R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); | ||
| 428 | } | ||
| 429 | |||
| 430 | Result StaticService::GetClockSnapshotFromSystemClockContext( | ||
| 431 | Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 432 | Service::PSC::Time::SystemClockContext& user_context, | ||
| 433 | Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) { | ||
| 434 | R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context, | ||
| 435 | network_context, type)); | ||
| 436 | } | ||
| 437 | |||
| 438 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser( | ||
| 439 | s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) { | ||
| 440 | R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); | ||
| 441 | } | ||
| 442 | |||
| 443 | Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, | ||
| 444 | Service::PSC::Time::ClockSnapshot& b) { | ||
| 445 | R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); | ||
| 446 | } | ||
| 447 | |||
| 448 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/static.h b/src/core/hle/service/glue/time/static.h new file mode 100644 index 000000000..75fe4e2cd --- /dev/null +++ b/src/core/hle/service/glue/time/static.h | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/service/glue/time/manager.h" | ||
| 8 | #include "core/hle/service/glue/time/time_zone.h" | ||
| 9 | #include "core/hle/service/psc/time/common.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Set { | ||
| 16 | class ISystemSettingsServer; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::PSC::Time { | ||
| 20 | class StaticService; | ||
| 21 | class SystemClock; | ||
| 22 | class SteadyClock; | ||
| 23 | class TimeZoneService; | ||
| 24 | class ServiceManager; | ||
| 25 | } // namespace Service::PSC::Time | ||
| 26 | |||
| 27 | namespace Service::Glue::Time { | ||
| 28 | class FileTimestampWorker; | ||
| 29 | class StandardSteadyClockResource; | ||
| 30 | |||
| 31 | class StaticService final : public ServiceFramework<StaticService> { | ||
| 32 | public: | ||
| 33 | explicit StaticService(Core::System& system, | ||
| 34 | Service::PSC::Time::StaticServiceSetupInfo setup_info, | ||
| 35 | std::shared_ptr<TimeManager> time, const char* name); | ||
| 36 | |||
| 37 | ~StaticService() override = default; | ||
| 38 | |||
| 39 | Result GetStandardUserSystemClock( | ||
| 40 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 41 | Result GetStandardNetworkSystemClock( | ||
| 42 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 43 | Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service); | ||
| 44 | Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service); | ||
| 45 | Result GetStandardLocalSystemClock( | ||
| 46 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 47 | Result GetEphemeralNetworkSystemClock( | ||
| 48 | std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); | ||
| 49 | Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); | ||
| 50 | Result SetStandardSteadyClockInternalOffset(s64 offset); | ||
| 51 | Result GetStandardSteadyClockRtcValue(s64& out_rtc_value); | ||
| 52 | Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction); | ||
| 53 | Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); | ||
| 54 | Result GetStandardUserSystemClockInitialYear(s32& out_year); | ||
| 55 | Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); | ||
| 56 | Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 57 | Service::PSC::Time::SteadyClockTimePoint& out_time_point); | ||
| 58 | Result CalculateMonotonicSystemClockBaseTimePoint( | ||
| 59 | s64& out_time, Service::PSC::Time::SystemClockContext& context); | ||
| 60 | Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 61 | Service::PSC::Time::TimeType type); | ||
| 62 | Result GetClockSnapshotFromSystemClockContext( | ||
| 63 | Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 64 | Service::PSC::Time::SystemClockContext& user_context, | ||
| 65 | Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type); | ||
| 66 | Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, | ||
| 67 | Service::PSC::Time::ClockSnapshot& a, | ||
| 68 | Service::PSC::Time::ClockSnapshot& b); | ||
| 69 | Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, | ||
| 70 | Service::PSC::Time::ClockSnapshot& b); | ||
| 71 | |||
| 72 | private: | ||
| 73 | Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot, | ||
| 74 | Service::PSC::Time::SystemClockContext& user_context, | ||
| 75 | Service::PSC::Time::SystemClockContext& network_context, | ||
| 76 | Service::PSC::Time::TimeType type); | ||
| 77 | |||
| 78 | void Handle_GetStandardUserSystemClock(HLERequestContext& ctx); | ||
| 79 | void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx); | ||
| 80 | void Handle_GetStandardSteadyClock(HLERequestContext& ctx); | ||
| 81 | void Handle_GetTimeZoneService(HLERequestContext& ctx); | ||
| 82 | void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx); | ||
| 83 | void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx); | ||
| 84 | void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx); | ||
| 85 | void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx); | ||
| 86 | void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx); | ||
| 87 | void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | ||
| 88 | void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | ||
| 89 | void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx); | ||
| 90 | void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); | ||
| 91 | void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); | ||
| 92 | void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); | ||
| 93 | void Handle_GetClockSnapshot(HLERequestContext& ctx); | ||
| 94 | void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); | ||
| 95 | void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); | ||
| 96 | void Handle_CalculateSpanBetween(HLERequestContext& ctx); | ||
| 97 | |||
| 98 | Core::System& m_system; | ||
| 99 | |||
| 100 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 101 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; | ||
| 102 | std::shared_ptr<Service::PSC::Time::StaticService> m_wrapped_service; | ||
| 103 | |||
| 104 | Service::PSC::Time::StaticServiceSetupInfo m_setup_info; | ||
| 105 | std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm; | ||
| 106 | std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone; | ||
| 107 | FileTimestampWorker& m_file_timestamp_worker; | ||
| 108 | StandardSteadyClockResource& m_standard_steady_clock_resource; | ||
| 109 | }; | ||
| 110 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp new file mode 100644 index 000000000..503c327dd --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone.cpp | |||
| @@ -0,0 +1,377 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/svc.h" | ||
| 8 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 9 | #include "core/hle/service/glue/time/time_zone.h" | ||
| 10 | #include "core/hle/service/glue/time/time_zone_binary.h" | ||
| 11 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 12 | #include "core/hle/service/set/system_settings_server.h" | ||
| 13 | #include "core/hle/service/sm/sm.h" | ||
| 14 | |||
| 15 | namespace Service::Glue::Time { | ||
| 16 | namespace { | ||
| 17 | static std::mutex g_list_mutex; | ||
| 18 | static Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType g_list_nodes{}; | ||
| 19 | } // namespace | ||
| 20 | |||
| 21 | TimeZoneService::TimeZoneService( | ||
| 22 | Core::System& system_, FileTimestampWorker& file_timestamp_worker, | ||
| 23 | bool can_write_timezone_device_location, | ||
| 24 | std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service) | ||
| 25 | : ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, | ||
| 26 | m_can_write_timezone_device_location{can_write_timezone_device_location}, | ||
| 27 | m_file_timestamp_worker{file_timestamp_worker}, | ||
| 28 | m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} { | ||
| 29 | // clang-format off | ||
| 30 | static const FunctionInfo functions[] = { | ||
| 31 | {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, | ||
| 32 | {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, | ||
| 33 | {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, | ||
| 34 | {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, | ||
| 35 | {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, | ||
| 36 | {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, | ||
| 37 | {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, | ||
| 38 | {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, | ||
| 39 | {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, | ||
| 40 | {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, | ||
| 41 | {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, | ||
| 42 | {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | ||
| 43 | {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, | ||
| 44 | {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, | ||
| 45 | }; | ||
| 46 | // clang-format on | ||
| 47 | RegisterHandlers(functions); | ||
| 48 | |||
| 49 | g_list_nodes.clear(); | ||
| 50 | m_set_sys = | ||
| 51 | m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 52 | } | ||
| 53 | |||
| 54 | TimeZoneService::~TimeZoneService() = default; | ||
| 55 | |||
| 56 | void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { | ||
| 57 | LOG_DEBUG(Service_Time, "called."); | ||
| 58 | |||
| 59 | Service::PSC::Time::LocationName name{}; | ||
| 60 | auto res = GetDeviceLocationName(name); | ||
| 61 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)}; | ||
| 63 | rb.Push(res); | ||
| 64 | rb.PushRaw<Service::PSC::Time::LocationName>(name); | ||
| 65 | } | ||
| 66 | |||
| 67 | void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) { | ||
| 68 | LOG_DEBUG(Service_Time, "called."); | ||
| 69 | |||
| 70 | IPC::RequestParser rp{ctx}; | ||
| 71 | auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; | ||
| 72 | |||
| 73 | auto res = SetDeviceLocation(name); | ||
| 74 | |||
| 75 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 76 | rb.Push(res); | ||
| 77 | } | ||
| 78 | |||
| 79 | void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) { | ||
| 80 | LOG_DEBUG(Service_Time, "called."); | ||
| 81 | |||
| 82 | u32 count{}; | ||
| 83 | auto res = GetTotalLocationNameCount(count); | ||
| 84 | |||
| 85 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 86 | rb.Push(res); | ||
| 87 | rb.Push(count); | ||
| 88 | } | ||
| 89 | |||
| 90 | void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) { | ||
| 91 | LOG_DEBUG(Service_Time, "called."); | ||
| 92 | |||
| 93 | IPC::RequestParser rp{ctx}; | ||
| 94 | auto index{rp.Pop<u32>()}; | ||
| 95 | |||
| 96 | auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)}; | ||
| 97 | |||
| 98 | std::vector<Service::PSC::Time::LocationName> names{}; | ||
| 99 | u32 count{}; | ||
| 100 | auto res = LoadLocationNameList(count, names, max_names, index); | ||
| 101 | |||
| 102 | ctx.WriteBuffer(names); | ||
| 103 | |||
| 104 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 105 | rb.Push(res); | ||
| 106 | rb.Push(count); | ||
| 107 | } | ||
| 108 | |||
| 109 | void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) { | ||
| 110 | LOG_DEBUG(Service_Time, "called."); | ||
| 111 | |||
| 112 | IPC::RequestParser rp{ctx}; | ||
| 113 | auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; | ||
| 114 | |||
| 115 | Tz::Rule rule{}; | ||
| 116 | auto res = LoadTimeZoneRule(rule, name); | ||
| 117 | |||
| 118 | ctx.WriteBuffer(rule); | ||
| 119 | |||
| 120 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 121 | rb.Push(res); | ||
| 122 | } | ||
| 123 | |||
| 124 | void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) { | ||
| 125 | LOG_DEBUG(Service_Time, "called."); | ||
| 126 | |||
| 127 | Service::PSC::Time::RuleVersion rule_version{}; | ||
| 128 | auto res = GetTimeZoneRuleVersion(rule_version); | ||
| 129 | |||
| 130 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)}; | ||
| 131 | rb.Push(res); | ||
| 132 | rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version); | ||
| 133 | } | ||
| 134 | |||
| 135 | void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) { | ||
| 136 | LOG_DEBUG(Service_Time, "called."); | ||
| 137 | |||
| 138 | Service::PSC::Time::LocationName name{}; | ||
| 139 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 140 | auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name); | ||
| 141 | |||
| 142 | IPC::ResponseBuilder rb{ctx, | ||
| 143 | 2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) + | ||
| 144 | (sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))}; | ||
| 145 | rb.Push(res); | ||
| 146 | rb.PushRaw<Service::PSC::Time::LocationName>(name); | ||
| 147 | rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); | ||
| 148 | } | ||
| 149 | |||
| 150 | void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) { | ||
| 151 | LOG_DEBUG(Service_Time, "called."); | ||
| 152 | |||
| 153 | auto res = SetDeviceLocationNameWithTimeZoneRule(); | ||
| 154 | |||
| 155 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 156 | rb.Push(res); | ||
| 157 | } | ||
| 158 | |||
| 159 | void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) { | ||
| 160 | LOG_DEBUG(Service_Time, "called."); | ||
| 161 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 163 | rb.Push(Service::PSC::Time::ResultNotImplemented); | ||
| 164 | } | ||
| 165 | |||
| 166 | void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle( | ||
| 167 | HLERequestContext& ctx) { | ||
| 168 | LOG_DEBUG(Service_Time, "called."); | ||
| 169 | |||
| 170 | Kernel::KEvent* event{}; | ||
| 171 | auto res = GetDeviceLocationNameOperationEventReadableHandle(&event); | ||
| 172 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 174 | rb.Push(res); | ||
| 175 | rb.PushCopyObjects(event->GetReadableEvent()); | ||
| 176 | } | ||
| 177 | |||
| 178 | void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) { | ||
| 179 | LOG_DEBUG(Service_Time, "called."); | ||
| 180 | |||
| 181 | IPC::RequestParser rp{ctx}; | ||
| 182 | auto time{rp.Pop<s64>()}; | ||
| 183 | |||
| 184 | auto rule_buffer{ctx.ReadBuffer()}; | ||
| 185 | Tz::Rule rule{}; | ||
| 186 | std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule)); | ||
| 187 | |||
| 188 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 189 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 190 | auto res = ToCalendarTime(calendar_time, additional_info, time, rule); | ||
| 191 | |||
| 192 | IPC::ResponseBuilder rb{ctx, | ||
| 193 | 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) + | ||
| 194 | (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))}; | ||
| 195 | rb.Push(res); | ||
| 196 | rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time); | ||
| 197 | rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info); | ||
| 198 | } | ||
| 199 | |||
| 200 | void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) { | ||
| 201 | IPC::RequestParser rp{ctx}; | ||
| 202 | auto time{rp.Pop<s64>()}; | ||
| 203 | |||
| 204 | LOG_DEBUG(Service_Time, "called. time={}", time); | ||
| 205 | |||
| 206 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 207 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 208 | auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time); | ||
| 209 | |||
| 210 | IPC::ResponseBuilder rb{ctx, | ||
| 211 | 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) + | ||
| 212 | (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))}; | ||
| 213 | rb.Push(res); | ||
| 214 | rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time); | ||
| 215 | rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info); | ||
| 216 | } | ||
| 217 | |||
| 218 | void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) { | ||
| 219 | IPC::RequestParser rp{ctx}; | ||
| 220 | auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()}; | ||
| 221 | |||
| 222 | LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}", | ||
| 223 | calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute, | ||
| 224 | calendar.second); | ||
| 225 | |||
| 226 | auto binary{ctx.ReadBuffer()}; | ||
| 227 | |||
| 228 | Tz::Rule rule{}; | ||
| 229 | std::memcpy(&rule, binary.data(), sizeof(Tz::Rule)); | ||
| 230 | |||
| 231 | u32 count{}; | ||
| 232 | std::array<s64, 2> times{}; | ||
| 233 | u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; | ||
| 234 | |||
| 235 | auto res = ToPosixTime(count, times, times_count, calendar, rule); | ||
| 236 | |||
| 237 | ctx.WriteBuffer(times); | ||
| 238 | |||
| 239 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 240 | rb.Push(res); | ||
| 241 | rb.Push(count); | ||
| 242 | } | ||
| 243 | |||
| 244 | void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) { | ||
| 245 | LOG_DEBUG(Service_Time, "called."); | ||
| 246 | |||
| 247 | IPC::RequestParser rp{ctx}; | ||
| 248 | auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()}; | ||
| 249 | |||
| 250 | u32 count{}; | ||
| 251 | std::array<s64, 2> times{}; | ||
| 252 | u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; | ||
| 253 | |||
| 254 | auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar); | ||
| 255 | |||
| 256 | ctx.WriteBuffer(times); | ||
| 257 | |||
| 258 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 259 | rb.Push(res); | ||
| 260 | rb.Push(count); | ||
| 261 | } | ||
| 262 | |||
| 263 | // =============================== Implementations =========================== | ||
| 264 | |||
| 265 | Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) { | ||
| 266 | R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); | ||
| 267 | } | ||
| 268 | |||
| 269 | Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) { | ||
| 270 | R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); | ||
| 271 | R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound); | ||
| 272 | |||
| 273 | std::scoped_lock l{m_mutex}; | ||
| 274 | |||
| 275 | std::span<const u8> binary{}; | ||
| 276 | size_t binary_size{}; | ||
| 277 | R_TRY(GetTimeZoneRule(binary, binary_size, location_name)) | ||
| 278 | |||
| 279 | R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary)); | ||
| 280 | |||
| 281 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 282 | |||
| 283 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 284 | Service::PSC::Time::LocationName name{}; | ||
| 285 | R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name)); | ||
| 286 | |||
| 287 | m_set_sys->SetDeviceTimeZoneLocationName(name); | ||
| 288 | m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point); | ||
| 289 | |||
| 290 | std::scoped_lock m{g_list_mutex}; | ||
| 291 | for (auto& operation_event : g_list_nodes) { | ||
| 292 | operation_event.m_event->Signal(); | ||
| 293 | } | ||
| 294 | R_SUCCEED(); | ||
| 295 | } | ||
| 296 | |||
| 297 | Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { | ||
| 298 | R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); | ||
| 299 | } | ||
| 300 | |||
| 301 | Result TimeZoneService::LoadLocationNameList( | ||
| 302 | u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names, | ||
| 303 | u32 index) { | ||
| 304 | std::scoped_lock l{m_mutex}; | ||
| 305 | R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index)); | ||
| 306 | } | ||
| 307 | |||
| 308 | Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule, | ||
| 309 | Service::PSC::Time::LocationName& name) { | ||
| 310 | std::scoped_lock l{m_mutex}; | ||
| 311 | std::span<const u8> binary{}; | ||
| 312 | size_t binary_size{}; | ||
| 313 | R_TRY(GetTimeZoneRule(binary, binary_size, name)) | ||
| 314 | R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary)); | ||
| 315 | } | ||
| 316 | |||
| 317 | Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) { | ||
| 318 | R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); | ||
| 319 | } | ||
| 320 | |||
| 321 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( | ||
| 322 | Service::PSC::Time::SteadyClockTimePoint& out_time_point, | ||
| 323 | Service::PSC::Time::LocationName& location_name) { | ||
| 324 | R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name)); | ||
| 325 | } | ||
| 326 | |||
| 327 | Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() { | ||
| 328 | R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); | ||
| 329 | R_RETURN(Service::PSC::Time::ResultNotImplemented); | ||
| 330 | } | ||
| 331 | |||
| 332 | Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle( | ||
| 333 | Kernel::KEvent** out_event) { | ||
| 334 | if (!operation_event_initialized) { | ||
| 335 | operation_event_initialized = false; | ||
| 336 | |||
| 337 | m_operation_event.m_ctx.CloseEvent(m_operation_event.m_event); | ||
| 338 | m_operation_event.m_event = | ||
| 339 | m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent"); | ||
| 340 | operation_event_initialized = true; | ||
| 341 | std::scoped_lock l{m_mutex}; | ||
| 342 | g_list_nodes.push_back(m_operation_event); | ||
| 343 | } | ||
| 344 | |||
| 345 | *out_event = m_operation_event.m_event; | ||
| 346 | R_SUCCEED(); | ||
| 347 | } | ||
| 348 | |||
| 349 | Result TimeZoneService::ToCalendarTime( | ||
| 350 | Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 351 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) { | ||
| 352 | R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); | ||
| 353 | } | ||
| 354 | |||
| 355 | Result TimeZoneService::ToCalendarTimeWithMyRule( | ||
| 356 | Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 357 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) { | ||
| 358 | R_RETURN( | ||
| 359 | m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); | ||
| 360 | } | ||
| 361 | |||
| 362 | Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, | ||
| 363 | u32 out_times_count, | ||
| 364 | Service::PSC::Time::CalendarTime& calendar_time, | ||
| 365 | Tz::Rule& rule) { | ||
| 366 | R_RETURN( | ||
| 367 | m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); | ||
| 368 | } | ||
| 369 | |||
| 370 | Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, | ||
| 371 | u32 out_times_count, | ||
| 372 | Service::PSC::Time::CalendarTime& calendar_time) { | ||
| 373 | R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count, | ||
| 374 | calendar_time)); | ||
| 375 | } | ||
| 376 | |||
| 377 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone.h b/src/core/hle/service/glue/time/time_zone.h new file mode 100644 index 000000000..3c8ae4bf8 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone.h | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <mutex> | ||
| 8 | #include <span> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "core/hle/service/ipc_helpers.h" | ||
| 12 | #include "core/hle/service/psc/time/common.h" | ||
| 13 | #include "core/hle/service/server_manager.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Tz { | ||
| 21 | struct Rule; | ||
| 22 | } | ||
| 23 | |||
| 24 | namespace Service::Set { | ||
| 25 | class ISystemSettingsServer; | ||
| 26 | } | ||
| 27 | |||
| 28 | namespace Service::PSC::Time { | ||
| 29 | class TimeZoneService; | ||
| 30 | } | ||
| 31 | |||
| 32 | namespace Service::Glue::Time { | ||
| 33 | class FileTimestampWorker; | ||
| 34 | |||
| 35 | class TimeZoneService final : public ServiceFramework<TimeZoneService> { | ||
| 36 | public: | ||
| 37 | explicit TimeZoneService( | ||
| 38 | Core::System& system, FileTimestampWorker& file_timestamp_worker, | ||
| 39 | bool can_write_timezone_device_location, | ||
| 40 | std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service); | ||
| 41 | |||
| 42 | ~TimeZoneService() override; | ||
| 43 | |||
| 44 | Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name); | ||
| 45 | Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name); | ||
| 46 | Result GetTotalLocationNameCount(u32& out_count); | ||
| 47 | Result LoadLocationNameList(u32& out_count, | ||
| 48 | std::vector<Service::PSC::Time::LocationName>& out_names, | ||
| 49 | size_t max_names, u32 index); | ||
| 50 | Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name); | ||
| 51 | Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version); | ||
| 52 | Result GetDeviceLocationNameAndUpdatedTime( | ||
| 53 | Service::PSC::Time::SteadyClockTimePoint& out_time_point, | ||
| 54 | Service::PSC::Time::LocationName& location_name); | ||
| 55 | Result SetDeviceLocationNameWithTimeZoneRule(); | ||
| 56 | Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event); | ||
| 57 | Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 58 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, | ||
| 59 | Tz::Rule& rule); | ||
| 60 | Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time, | ||
| 61 | Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, | ||
| 62 | s64 time); | ||
| 63 | Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 64 | Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule); | ||
| 65 | Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 66 | Service::PSC::Time::CalendarTime& calendar_time); | ||
| 67 | |||
| 68 | private: | ||
| 69 | void Handle_GetDeviceLocationName(HLERequestContext& ctx); | ||
| 70 | void Handle_SetDeviceLocationName(HLERequestContext& ctx); | ||
| 71 | void Handle_GetTotalLocationNameCount(HLERequestContext& ctx); | ||
| 72 | void Handle_LoadLocationNameList(HLERequestContext& ctx); | ||
| 73 | void Handle_LoadTimeZoneRule(HLERequestContext& ctx); | ||
| 74 | void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx); | ||
| 75 | void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx); | ||
| 76 | void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx); | ||
| 77 | void Handle_ParseTimeZoneBinary(HLERequestContext& ctx); | ||
| 78 | void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx); | ||
| 79 | void Handle_ToCalendarTime(HLERequestContext& ctx); | ||
| 80 | void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx); | ||
| 81 | void Handle_ToPosixTime(HLERequestContext& ctx); | ||
| 82 | void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx); | ||
| 83 | |||
| 84 | Core::System& m_system; | ||
| 85 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 86 | |||
| 87 | bool m_can_write_timezone_device_location; | ||
| 88 | FileTimestampWorker& m_file_timestamp_worker; | ||
| 89 | std::shared_ptr<Service::PSC::Time::TimeZoneService> m_wrapped_service; | ||
| 90 | std::mutex m_mutex; | ||
| 91 | bool operation_event_initialized{}; | ||
| 92 | Service::PSC::Time::OperationEvent m_operation_event; | ||
| 93 | }; | ||
| 94 | |||
| 95 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp new file mode 100644 index 000000000..67969aa3f --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone_binary.cpp | |||
| @@ -0,0 +1,221 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/file_sys/content_archive.h" | ||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/registered_cache.h" | ||
| 8 | #include "core/file_sys/romfs.h" | ||
| 9 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 10 | #include "core/file_sys/vfs.h" | ||
| 11 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 12 | #include "core/hle/service/glue/time/time_zone_binary.h" | ||
| 13 | |||
| 14 | namespace Service::Glue::Time { | ||
| 15 | namespace { | ||
| 16 | constexpr u64 TimeZoneBinaryId = 0x10000000000080E; | ||
| 17 | |||
| 18 | static FileSys::VirtualDir g_time_zone_binary_romfs{}; | ||
| 19 | static Result g_time_zone_binary_mount_result{ResultUnknown}; | ||
| 20 | static std::vector<u8> g_time_zone_scratch_space(0x2800, 0); | ||
| 21 | |||
| 22 | Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size, | ||
| 23 | std::string_view path) { | ||
| 24 | R_UNLESS(g_time_zone_binary_mount_result == ResultSuccess, g_time_zone_binary_mount_result); | ||
| 25 | |||
| 26 | auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; | ||
| 27 | R_UNLESS(vfs_file, ResultUnknown); | ||
| 28 | |||
| 29 | auto file_size{vfs_file->GetSize()}; | ||
| 30 | R_UNLESS(file_size > 0, ResultUnknown); | ||
| 31 | |||
| 32 | R_UNLESS(file_size <= out_buffer_size, Service::PSC::Time::ResultFailed); | ||
| 33 | |||
| 34 | out_read_size = vfs_file->Read(out_buffer.data(), file_size); | ||
| 35 | R_UNLESS(out_read_size > 0, ResultUnknown); | ||
| 36 | |||
| 37 | R_SUCCEED(); | ||
| 38 | } | ||
| 39 | } // namespace | ||
| 40 | |||
| 41 | void ResetTimeZoneBinary() { | ||
| 42 | g_time_zone_binary_romfs = {}; | ||
| 43 | g_time_zone_binary_mount_result = ResultUnknown; | ||
| 44 | g_time_zone_scratch_space.clear(); | ||
| 45 | g_time_zone_scratch_space.resize(0x2800, 0); | ||
| 46 | } | ||
| 47 | |||
| 48 | Result MountTimeZoneBinary(Core::System& system) { | ||
| 49 | ResetTimeZoneBinary(); | ||
| 50 | |||
| 51 | auto& fsc{system.GetFileSystemController()}; | ||
| 52 | std::unique_ptr<FileSys::NCA> nca{}; | ||
| 53 | |||
| 54 | auto* bis_system = fsc.GetSystemNANDContents(); | ||
| 55 | |||
| 56 | R_UNLESS(bis_system, ResultUnknown); | ||
| 57 | |||
| 58 | nca = bis_system->GetEntry(TimeZoneBinaryId, FileSys::ContentRecordType::Data); | ||
| 59 | |||
| 60 | if (nca) { | ||
| 61 | g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS()); | ||
| 62 | } | ||
| 63 | |||
| 64 | if (g_time_zone_binary_romfs) { | ||
| 65 | // Validate that the romfs is readable, using invalid firmware keys can cause this to get | ||
| 66 | // set but the files to be garbage. In that case, we want to hit the next path and | ||
| 67 | // synthesise them instead. | ||
| 68 | Service::PSC::Time::LocationName name{"Etc/GMT"}; | ||
| 69 | if (!IsTimeZoneBinaryValid(name)) { | ||
| 70 | ResetTimeZoneBinary(); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | if (!g_time_zone_binary_romfs) { | ||
| 75 | g_time_zone_binary_romfs = FileSys::ExtractRomFS( | ||
| 76 | FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId)); | ||
| 77 | } | ||
| 78 | |||
| 79 | R_UNLESS(g_time_zone_binary_romfs, ResultUnknown); | ||
| 80 | |||
| 81 | g_time_zone_binary_mount_result = ResultSuccess; | ||
| 82 | R_SUCCEED(); | ||
| 83 | } | ||
| 84 | |||
| 85 | void GetTimeZoneBinaryListPath(std::string& out_path) { | ||
| 86 | if (g_time_zone_binary_mount_result != ResultSuccess) { | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | // out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary"); | ||
| 90 | out_path = "/binaryList.txt"; | ||
| 91 | } | ||
| 92 | |||
| 93 | void GetTimeZoneBinaryVersionPath(std::string& out_path) { | ||
| 94 | if (g_time_zone_binary_mount_result != ResultSuccess) { | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | // out_path = fmt::format("{}:/version.txt", "TimeZoneBinary"); | ||
| 98 | out_path = "/version.txt"; | ||
| 99 | } | ||
| 100 | |||
| 101 | void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) { | ||
| 102 | if (g_time_zone_binary_mount_result != ResultSuccess) { | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name); | ||
| 106 | out_path = fmt::format("/zoneinfo/{}", name.name.data()); | ||
| 107 | } | ||
| 108 | |||
| 109 | bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) { | ||
| 110 | std::string path{}; | ||
| 111 | GetTimeZoneZonePath(path, name); | ||
| 112 | |||
| 113 | auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; | ||
| 114 | if (!vfs_file) { | ||
| 115 | LOG_INFO(Service_Time, "Could not find timezone file {}", path); | ||
| 116 | return false; | ||
| 117 | } | ||
| 118 | return vfs_file->GetSize() != 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | u32 GetTimeZoneCount() { | ||
| 122 | std::string path{}; | ||
| 123 | GetTimeZoneBinaryListPath(path); | ||
| 124 | |||
| 125 | size_t bytes_read{}; | ||
| 126 | if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) { | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | if (bytes_read == 0) { | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read); | ||
| 134 | u32 count{}; | ||
| 135 | for (auto chr : chars) { | ||
| 136 | if (chr == '\n') { | ||
| 137 | count++; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | return count; | ||
| 141 | } | ||
| 142 | |||
| 143 | Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) { | ||
| 144 | std::string path{}; | ||
| 145 | GetTimeZoneBinaryVersionPath(path); | ||
| 146 | |||
| 147 | auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version), | ||
| 148 | sizeof(Service::PSC::Time::RuleVersion))}; | ||
| 149 | size_t bytes_read{}; | ||
| 150 | R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(), | ||
| 151 | path)); | ||
| 152 | |||
| 153 | rule_version_buffer[bytes_read] = 0; | ||
| 154 | R_SUCCEED(); | ||
| 155 | } | ||
| 156 | |||
| 157 | Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, | ||
| 158 | Service::PSC::Time::LocationName& name) { | ||
| 159 | std::string path{}; | ||
| 160 | GetTimeZoneZonePath(path, name); | ||
| 161 | |||
| 162 | size_t bytes_read{}; | ||
| 163 | R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, | ||
| 164 | g_time_zone_scratch_space.size(), path)); | ||
| 165 | |||
| 166 | out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read); | ||
| 167 | out_rule_size = bytes_read; | ||
| 168 | R_SUCCEED(); | ||
| 169 | } | ||
| 170 | |||
| 171 | Result GetTimeZoneLocationList(u32& out_count, | ||
| 172 | std::vector<Service::PSC::Time::LocationName>& out_names, | ||
| 173 | size_t max_names, u32 index) { | ||
| 174 | std::string path{}; | ||
| 175 | GetTimeZoneBinaryListPath(path); | ||
| 176 | |||
| 177 | size_t bytes_read{}; | ||
| 178 | R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, | ||
| 179 | g_time_zone_scratch_space.size(), path)); | ||
| 180 | |||
| 181 | out_count = 0; | ||
| 182 | R_SUCCEED_IF(bytes_read == 0); | ||
| 183 | |||
| 184 | Service::PSC::Time::LocationName current_name{}; | ||
| 185 | size_t current_name_len{}; | ||
| 186 | std::span<const u8> chars{g_time_zone_scratch_space}; | ||
| 187 | u32 name_count{}; | ||
| 188 | |||
| 189 | for (auto chr : chars) { | ||
| 190 | if (chr == '\r') { | ||
| 191 | continue; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (chr == '\n') { | ||
| 195 | if (name_count >= index) { | ||
| 196 | out_names.push_back(current_name); | ||
| 197 | out_count++; | ||
| 198 | if (out_count >= max_names) { | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | name_count++; | ||
| 203 | current_name_len = 0; | ||
| 204 | current_name = {}; | ||
| 205 | continue; | ||
| 206 | } | ||
| 207 | |||
| 208 | if (chr == '\0') { | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | |||
| 212 | R_UNLESS(current_name_len <= current_name.name.size() - 2, | ||
| 213 | Service::PSC::Time::ResultFailed); | ||
| 214 | |||
| 215 | current_name.name[current_name_len++] = chr; | ||
| 216 | } | ||
| 217 | |||
| 218 | R_SUCCEED(); | ||
| 219 | } | ||
| 220 | |||
| 221 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/time_zone_binary.h b/src/core/hle/service/glue/time/time_zone_binary.h new file mode 100644 index 000000000..2cad6b458 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone_binary.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <span> | ||
| 7 | #include <string> | ||
| 8 | #include <string_view> | ||
| 9 | |||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Glue::Time { | ||
| 17 | |||
| 18 | void ResetTimeZoneBinary(); | ||
| 19 | Result MountTimeZoneBinary(Core::System& system); | ||
| 20 | void GetTimeZoneBinaryListPath(std::string& out_path); | ||
| 21 | void GetTimeZoneBinaryVersionPath(std::string& out_path); | ||
| 22 | void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name); | ||
| 23 | bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name); | ||
| 24 | u32 GetTimeZoneCount(); | ||
| 25 | Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version); | ||
| 26 | Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, | ||
| 27 | Service::PSC::Time::LocationName& name); | ||
| 28 | Result GetTimeZoneLocationList(u32& out_count, | ||
| 29 | std::vector<Service::PSC::Time::LocationName>& out_names, | ||
| 30 | size_t max_names, u32 index); | ||
| 31 | |||
| 32 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp new file mode 100644 index 000000000..ea0e49b90 --- /dev/null +++ b/src/core/hle/service/glue/time/worker.cpp | |||
| @@ -0,0 +1,338 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/scope_exit.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hle/service/glue/time/file_timestamp_worker.h" | ||
| 8 | #include "core/hle/service/glue/time/standard_steady_clock_resource.h" | ||
| 9 | #include "core/hle/service/glue/time/worker.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 12 | #include "core/hle/service/psc/time/static.h" | ||
| 13 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 14 | #include "core/hle/service/set/system_settings_server.h" | ||
| 15 | #include "core/hle/service/sm/sm.h" | ||
| 16 | |||
| 17 | namespace Service::Glue::Time { | ||
| 18 | namespace { | ||
| 19 | |||
| 20 | bool g_ig_report_network_clock_context_set{}; | ||
| 21 | Service::PSC::Time::SystemClockContext g_report_network_clock_context{}; | ||
| 22 | bool g_ig_report_ephemeral_clock_context_set{}; | ||
| 23 | Service::PSC::Time::SystemClockContext g_report_ephemeral_clock_context{}; | ||
| 24 | |||
| 25 | template <typename T> | ||
| 26 | T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, | ||
| 27 | const char* category, const char* name) { | ||
| 28 | std::vector<u8> interval_buf; | ||
| 29 | auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); | ||
| 30 | ASSERT(res == ResultSuccess); | ||
| 31 | |||
| 32 | T v{}; | ||
| 33 | std::memcpy(&v, interval_buf.data(), sizeof(T)); | ||
| 34 | return v; | ||
| 35 | } | ||
| 36 | |||
| 37 | } // namespace | ||
| 38 | |||
| 39 | TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, | ||
| 40 | FileTimestampWorker& file_timestamp_worker) | ||
| 41 | : m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")}, | ||
| 42 | m_steady_clock_resource{steady_clock_resource}, | ||
| 43 | m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent( | ||
| 44 | "Glue:58:SteadyClockTimerEvent")}, | ||
| 45 | m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")}, | ||
| 46 | m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} { | ||
| 47 | g_ig_report_network_clock_context_set = false; | ||
| 48 | g_report_network_clock_context = {}; | ||
| 49 | g_ig_report_ephemeral_clock_context_set = false; | ||
| 50 | g_report_ephemeral_clock_context = {}; | ||
| 51 | |||
| 52 | m_timer_steady_clock_timing_event = Core::Timing::CreateEvent( | ||
| 53 | "Time::SteadyClockEvent", | ||
| 54 | [this](s64 time, | ||
| 55 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 56 | m_timer_steady_clock->Signal(); | ||
| 57 | return std::nullopt; | ||
| 58 | }); | ||
| 59 | |||
| 60 | m_timer_file_system_timing_event = Core::Timing::CreateEvent( | ||
| 61 | "Time::SteadyClockEvent", | ||
| 62 | [this](s64 time, | ||
| 63 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 64 | m_timer_file_system->Signal(); | ||
| 65 | return std::nullopt; | ||
| 66 | }); | ||
| 67 | } | ||
| 68 | |||
| 69 | TimeWorker::~TimeWorker() { | ||
| 70 | m_local_clock_event->Signal(); | ||
| 71 | m_network_clock_event->Signal(); | ||
| 72 | m_ephemeral_clock_event->Signal(); | ||
| 73 | std::this_thread::sleep_for(std::chrono::milliseconds(16)); | ||
| 74 | |||
| 75 | m_thread.request_stop(); | ||
| 76 | m_event->Signal(); | ||
| 77 | m_thread.join(); | ||
| 78 | |||
| 79 | m_ctx.CloseEvent(m_event); | ||
| 80 | m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event); | ||
| 81 | m_ctx.CloseEvent(m_timer_steady_clock); | ||
| 82 | m_system.CoreTiming().UnscheduleEvent(m_timer_file_system_timing_event); | ||
| 83 | m_ctx.CloseEvent(m_timer_file_system); | ||
| 84 | } | ||
| 85 | |||
| 86 | void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, | ||
| 87 | std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) { | ||
| 88 | m_set_sys = std::move(set_sys); | ||
| 89 | m_time_m = | ||
| 90 | m_system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); | ||
| 91 | m_time_sm = std::move(time_sm); | ||
| 92 | |||
| 93 | m_alarm_worker.Initialize(m_time_m); | ||
| 94 | |||
| 95 | auto steady_clock_interval_m = GetSettingsItemValue<s32>( | ||
| 96 | m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes"); | ||
| 97 | |||
| 98 | auto one_minute_ns{ | ||
| 99 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; | ||
| 100 | s64 steady_clock_interval_ns{steady_clock_interval_m * one_minute_ns}; | ||
| 101 | |||
| 102 | m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), | ||
| 103 | std::chrono::nanoseconds(steady_clock_interval_ns), | ||
| 104 | m_timer_steady_clock_timing_event); | ||
| 105 | |||
| 106 | auto fs_notify_time_s = | ||
| 107 | GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds"); | ||
| 108 | auto one_second_ns{ | ||
| 109 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 110 | s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns}; | ||
| 111 | |||
| 112 | m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), | ||
| 113 | std::chrono::nanoseconds(fs_notify_time_ns), | ||
| 114 | m_timer_file_system_timing_event); | ||
| 115 | |||
| 116 | auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock); | ||
| 117 | ASSERT(res == ResultSuccess); | ||
| 118 | res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event); | ||
| 119 | ASSERT(res == ResultSuccess); | ||
| 120 | |||
| 121 | res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock); | ||
| 122 | ASSERT(res == ResultSuccess); | ||
| 123 | res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event); | ||
| 124 | ASSERT(res == ResultSuccess); | ||
| 125 | |||
| 126 | res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock); | ||
| 127 | ASSERT(res == ResultSuccess); | ||
| 128 | res = | ||
| 129 | m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event); | ||
| 130 | ASSERT(res == ResultSuccess); | ||
| 131 | |||
| 132 | res = m_time_m->GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( | ||
| 133 | &m_standard_user_auto_correct_clock_event); | ||
| 134 | ASSERT(res == ResultSuccess); | ||
| 135 | } | ||
| 136 | |||
| 137 | void TimeWorker::StartThread() { | ||
| 138 | m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this)); | ||
| 139 | } | ||
| 140 | |||
| 141 | void TimeWorker::ThreadFunc(std::stop_token stop_token) { | ||
| 142 | Common::SetCurrentThreadName("TimeWorker"); | ||
| 143 | Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); | ||
| 144 | |||
| 145 | enum class EventType { | ||
| 146 | Exit = 0, | ||
| 147 | IpmModuleService_GetEvent = 1, | ||
| 148 | PowerStateChange = 2, | ||
| 149 | SignalAlarms = 3, | ||
| 150 | UpdateLocalSystemClock = 4, | ||
| 151 | UpdateNetworkSystemClock = 5, | ||
| 152 | UpdateEphemeralSystemClock = 6, | ||
| 153 | UpdateSteadyClock = 7, | ||
| 154 | UpdateFileTimestamp = 8, | ||
| 155 | AutoCorrect = 9, | ||
| 156 | Max = 10, | ||
| 157 | }; | ||
| 158 | |||
| 159 | s32 num_objs{}; | ||
| 160 | std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{}; | ||
| 161 | std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{}; | ||
| 162 | |||
| 163 | const auto AddWaiter{ | ||
| 164 | [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) { | ||
| 165 | // Open a new reference to the object. | ||
| 166 | synchronization_object->Open(); | ||
| 167 | |||
| 168 | // Insert into the list. | ||
| 169 | wait_indices[num_objs] = type; | ||
| 170 | wait_objs[num_objs++] = synchronization_object; | ||
| 171 | }}; | ||
| 172 | |||
| 173 | while (!stop_token.stop_requested()) { | ||
| 174 | SCOPE_EXIT({ | ||
| 175 | for (s32 i = 0; i < num_objs; i++) { | ||
| 176 | wait_objs[i]->Close(); | ||
| 177 | } | ||
| 178 | }); | ||
| 179 | |||
| 180 | num_objs = {}; | ||
| 181 | wait_objs = {}; | ||
| 182 | if (m_pm_state_change_handler.m_priority != 0) { | ||
| 183 | AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); | ||
| 184 | // TODO | ||
| 185 | // AddWaiter(gIPmModuleService::GetEvent(), 1); | ||
| 186 | AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); | ||
| 187 | } else { | ||
| 188 | AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); | ||
| 189 | // TODO | ||
| 190 | // AddWaiter(gIPmModuleService::GetEvent(), 1); | ||
| 191 | AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); | ||
| 192 | AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); | ||
| 193 | AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock); | ||
| 194 | AddWaiter(&m_network_clock_event->GetReadableEvent(), | ||
| 195 | EventType::UpdateNetworkSystemClock); | ||
| 196 | AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(), | ||
| 197 | EventType::UpdateEphemeralSystemClock); | ||
| 198 | AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); | ||
| 199 | AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); | ||
| 200 | AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(), | ||
| 201 | EventType::AutoCorrect); | ||
| 202 | } | ||
| 203 | |||
| 204 | s32 out_index{-1}; | ||
| 205 | Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), | ||
| 206 | num_objs, -1); | ||
| 207 | ASSERT(out_index >= 0 && out_index < num_objs); | ||
| 208 | |||
| 209 | if (stop_token.stop_requested()) { | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | |||
| 213 | switch (wait_indices[out_index]) { | ||
| 214 | case EventType::Exit: | ||
| 215 | return; | ||
| 216 | |||
| 217 | case EventType::IpmModuleService_GetEvent: | ||
| 218 | // TODO | ||
| 219 | // IPmModuleService::GetEvent() | ||
| 220 | // clear the event | ||
| 221 | // Handle power state change event | ||
| 222 | break; | ||
| 223 | |||
| 224 | case EventType::PowerStateChange: | ||
| 225 | m_alarm_worker.GetEvent().Clear(); | ||
| 226 | if (m_pm_state_change_handler.m_priority <= 1) { | ||
| 227 | m_alarm_worker.OnPowerStateChanged(); | ||
| 228 | } | ||
| 229 | break; | ||
| 230 | |||
| 231 | case EventType::SignalAlarms: | ||
| 232 | m_alarm_worker.GetTimerEvent().Clear(); | ||
| 233 | m_time_m->CheckAndSignalAlarms(); | ||
| 234 | break; | ||
| 235 | |||
| 236 | case EventType::UpdateLocalSystemClock: { | ||
| 237 | m_local_clock_event->Clear(); | ||
| 238 | |||
| 239 | Service::PSC::Time::SystemClockContext context{}; | ||
| 240 | auto res = m_local_clock->GetSystemClockContext(context); | ||
| 241 | ASSERT(res == ResultSuccess); | ||
| 242 | |||
| 243 | m_set_sys->SetUserSystemClockContext(context); | ||
| 244 | |||
| 245 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 246 | } break; | ||
| 247 | |||
| 248 | case EventType::UpdateNetworkSystemClock: { | ||
| 249 | m_network_clock_event->Clear(); | ||
| 250 | Service::PSC::Time::SystemClockContext context{}; | ||
| 251 | auto res = m_network_clock->GetSystemClockContext(context); | ||
| 252 | ASSERT(res == ResultSuccess); | ||
| 253 | m_set_sys->SetNetworkSystemClockContext(context); | ||
| 254 | |||
| 255 | s64 time{}; | ||
| 256 | if (m_network_clock->GetCurrentTime(time) != ResultSuccess) { | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | |||
| 260 | [[maybe_unused]] auto offset_before{ | ||
| 261 | g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0}; | ||
| 262 | // TODO system report "standard_netclock_operation" | ||
| 263 | // "clock_time" = time | ||
| 264 | // "context_offset_before" = offset_before | ||
| 265 | // "context_offset_after" = context.offset | ||
| 266 | g_report_network_clock_context = context; | ||
| 267 | if (!g_ig_report_network_clock_context_set) { | ||
| 268 | g_ig_report_network_clock_context_set = true; | ||
| 269 | } | ||
| 270 | |||
| 271 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 272 | } break; | ||
| 273 | |||
| 274 | case EventType::UpdateEphemeralSystemClock: { | ||
| 275 | m_ephemeral_clock_event->Clear(); | ||
| 276 | |||
| 277 | Service::PSC::Time::SystemClockContext context{}; | ||
| 278 | auto res = m_ephemeral_clock->GetSystemClockContext(context); | ||
| 279 | if (res != ResultSuccess) { | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | |||
| 283 | s64 time{}; | ||
| 284 | res = m_ephemeral_clock->GetCurrentTime(time); | ||
| 285 | if (res != ResultSuccess) { | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | |||
| 289 | [[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set | ||
| 290 | ? g_report_ephemeral_clock_context.offset | ||
| 291 | : 0}; | ||
| 292 | // TODO system report "ephemeral_netclock_operation" | ||
| 293 | // "clock_time" = time | ||
| 294 | // "context_offset_before" = offset_before | ||
| 295 | // "context_offset_after" = context.offset | ||
| 296 | g_report_ephemeral_clock_context = context; | ||
| 297 | if (!g_ig_report_ephemeral_clock_context_set) { | ||
| 298 | g_ig_report_ephemeral_clock_context_set = true; | ||
| 299 | } | ||
| 300 | } break; | ||
| 301 | |||
| 302 | case EventType::UpdateSteadyClock: | ||
| 303 | m_timer_steady_clock->Clear(); | ||
| 304 | |||
| 305 | m_steady_clock_resource.UpdateTime(); | ||
| 306 | m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime()); | ||
| 307 | break; | ||
| 308 | |||
| 309 | case EventType::UpdateFileTimestamp: | ||
| 310 | m_timer_file_system->Clear(); | ||
| 311 | |||
| 312 | m_file_timestamp_worker.SetFilesystemPosixTime(); | ||
| 313 | break; | ||
| 314 | |||
| 315 | case EventType::AutoCorrect: { | ||
| 316 | m_standard_user_auto_correct_clock_event->Clear(); | ||
| 317 | |||
| 318 | bool automatic_correction{}; | ||
| 319 | auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 320 | automatic_correction); | ||
| 321 | ASSERT(res == ResultSuccess); | ||
| 322 | |||
| 323 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 324 | res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 325 | ASSERT(res == ResultSuccess); | ||
| 326 | |||
| 327 | m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction); | ||
| 328 | m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 329 | } break; | ||
| 330 | |||
| 331 | default: | ||
| 332 | UNREACHABLE(); | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/glue/time/worker.h b/src/core/hle/service/glue/time/worker.h new file mode 100644 index 000000000..adbbe6b6d --- /dev/null +++ b/src/core/hle/service/glue/time/worker.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 8 | #include "core/hle/service/glue/time/alarm_worker.h" | ||
| 9 | #include "core/hle/service/glue/time/pm_state_change_handler.h" | ||
| 10 | #include "core/hle/service/kernel_helpers.h" | ||
| 11 | |||
| 12 | namespace Service::Set { | ||
| 13 | class ISystemSettingsServer; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::PSC::Time { | ||
| 17 | class StaticService; | ||
| 18 | class SystemClock; | ||
| 19 | } // namespace Service::PSC::Time | ||
| 20 | |||
| 21 | namespace Service::Glue::Time { | ||
| 22 | class FileTimestampWorker; | ||
| 23 | class StandardSteadyClockResource; | ||
| 24 | |||
| 25 | class TimeWorker { | ||
| 26 | public: | ||
| 27 | explicit TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, | ||
| 28 | FileTimestampWorker& file_timestamp_worker); | ||
| 29 | ~TimeWorker(); | ||
| 30 | |||
| 31 | void Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, | ||
| 32 | std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys); | ||
| 33 | |||
| 34 | void StartThread(); | ||
| 35 | |||
| 36 | private: | ||
| 37 | void ThreadFunc(std::stop_token stop_token); | ||
| 38 | |||
| 39 | Core::System& m_system; | ||
| 40 | KernelHelpers::ServiceContext m_ctx; | ||
| 41 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 42 | |||
| 43 | std::jthread m_thread; | ||
| 44 | Kernel::KEvent* m_event{}; | ||
| 45 | std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; | ||
| 46 | std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm; | ||
| 47 | std::shared_ptr<Service::PSC::Time::SystemClock> m_network_clock; | ||
| 48 | std::shared_ptr<Service::PSC::Time::SystemClock> m_local_clock; | ||
| 49 | std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock; | ||
| 50 | StandardSteadyClockResource& m_steady_clock_resource; | ||
| 51 | FileTimestampWorker& m_file_timestamp_worker; | ||
| 52 | Kernel::KEvent* m_local_clock_event{}; | ||
| 53 | Kernel::KEvent* m_network_clock_event{}; | ||
| 54 | Kernel::KEvent* m_ephemeral_clock_event{}; | ||
| 55 | Kernel::KEvent* m_standard_user_auto_correct_clock_event{}; | ||
| 56 | Kernel::KEvent* m_timer_steady_clock{}; | ||
| 57 | std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event; | ||
| 58 | Kernel::KEvent* m_timer_file_system{}; | ||
| 59 | std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event; | ||
| 60 | AlarmWorker m_alarm_worker; | ||
| 61 | PmStateChangeHandler m_pm_state_change_handler; | ||
| 62 | }; | ||
| 63 | |||
| 64 | } // namespace Service::Glue::Time | ||
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp index f51e63564..f080f7ffa 100644 --- a/src/core/hle/service/kernel_helpers.cpp +++ b/src/core/hle/service/kernel_helpers.cpp | |||
| @@ -65,6 +65,9 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void ServiceContext::CloseEvent(Kernel::KEvent* event) { | 67 | void ServiceContext::CloseEvent(Kernel::KEvent* event) { |
| 68 | if (!event) { | ||
| 69 | return; | ||
| 70 | } | ||
| 68 | event->GetReadableEvent().Close(); | 71 | event->GetReadableEvent().Close(); |
| 69 | event->Close(); | 72 | event->Close(); |
| 70 | } | 73 | } |
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index cc7776efc..1e2d2d212 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/glue/time/static.h" | ||
| 5 | #include "core/hle/service/psc/time/steady_clock.h" | ||
| 4 | #ifdef _MSC_VER | 6 | #ifdef _MSC_VER |
| 5 | #pragma warning(push) | 7 | #pragma warning(push) |
| 6 | #pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used | 8 | #pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used |
| @@ -29,7 +31,8 @@ | |||
| 29 | #include "core/hle/service/nfc/common/device.h" | 31 | #include "core/hle/service/nfc/common/device.h" |
| 30 | #include "core/hle/service/nfc/mifare_result.h" | 32 | #include "core/hle/service/nfc/mifare_result.h" |
| 31 | #include "core/hle/service/nfc/nfc_result.h" | 33 | #include "core/hle/service/nfc/nfc_result.h" |
| 32 | #include "core/hle/service/time/time_manager.h" | 34 | #include "core/hle/service/service.h" |
| 35 | #include "core/hle/service/sm/sm.h" | ||
| 33 | #include "hid_core/frontend/emulated_controller.h" | 36 | #include "hid_core/frontend/emulated_controller.h" |
| 34 | #include "hid_core/hid_core.h" | 37 | #include "hid_core/hid_core.h" |
| 35 | #include "hid_core/hid_types.h" | 38 | #include "hid_core/hid_types.h" |
| @@ -393,8 +396,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet | |||
| 393 | return result; | 396 | return result; |
| 394 | } | 397 | } |
| 395 | 398 | ||
| 396 | Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, | 399 | Result NfcDevice::SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data, |
| 397 | std::span<const u8> command_data, | ||
| 398 | std::span<u8> out_data) { | 400 | std::span<u8> out_data) { |
| 399 | // Not implemented | 401 | // Not implemented |
| 400 | return ResultSuccess; | 402 | return ResultSuccess; |
| @@ -1399,27 +1401,41 @@ void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, | |||
| 1399 | } | 1401 | } |
| 1400 | 1402 | ||
| 1401 | NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const { | 1403 | NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const { |
| 1402 | const auto& time_zone_manager = | 1404 | auto static_service = |
| 1403 | system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); | 1405 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); |
| 1404 | Time::TimeZone::CalendarInfo calendar_info{}; | 1406 | |
| 1407 | std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{}; | ||
| 1408 | static_service->GetTimeZoneService(timezone_service); | ||
| 1409 | |||
| 1410 | Service::PSC::Time::CalendarTime calendar_time{}; | ||
| 1411 | Service::PSC::Time::CalendarAdditionalInfo additional_info{}; | ||
| 1412 | |||
| 1405 | NFP::AmiiboDate amiibo_date{}; | 1413 | NFP::AmiiboDate amiibo_date{}; |
| 1406 | 1414 | ||
| 1407 | amiibo_date.SetYear(2000); | 1415 | amiibo_date.SetYear(2000); |
| 1408 | amiibo_date.SetMonth(1); | 1416 | amiibo_date.SetMonth(1); |
| 1409 | amiibo_date.SetDay(1); | 1417 | amiibo_date.SetDay(1); |
| 1410 | 1418 | ||
| 1411 | if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { | 1419 | if (timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time) == |
| 1412 | amiibo_date.SetYear(calendar_info.time.year); | 1420 | ResultSuccess) { |
| 1413 | amiibo_date.SetMonth(calendar_info.time.month); | 1421 | amiibo_date.SetYear(calendar_time.year); |
| 1414 | amiibo_date.SetDay(calendar_info.time.day); | 1422 | amiibo_date.SetMonth(calendar_time.month); |
| 1423 | amiibo_date.SetDay(calendar_time.day); | ||
| 1415 | } | 1424 | } |
| 1416 | 1425 | ||
| 1417 | return amiibo_date; | 1426 | return amiibo_date; |
| 1418 | } | 1427 | } |
| 1419 | 1428 | ||
| 1420 | u64 NfcDevice::GetCurrentPosixTime() const { | 1429 | s64 NfcDevice::GetCurrentPosixTime() const { |
| 1421 | auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; | 1430 | auto static_service = |
| 1422 | return standard_steady_clock.GetCurrentTimePoint(system).time_point; | 1431 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); |
| 1432 | |||
| 1433 | std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; | ||
| 1434 | static_service->GetStandardSteadyClock(steady_clock); | ||
| 1435 | |||
| 1436 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 1437 | R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); | ||
| 1438 | return time_point.time_point; | ||
| 1423 | } | 1439 | } |
| 1424 | 1440 | ||
| 1425 | u64 NfcDevice::RemoveVersionByte(u64 application_id) const { | 1441 | u64 NfcDevice::RemoveVersionByte(u64 application_id) const { |
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index 15f9b25da..d59202d18 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include "core/hle/service/nfc/nfc_types.h" | 11 | #include "core/hle/service/nfc/nfc_types.h" |
| 12 | #include "core/hle/service/nfp/nfp_types.h" | 12 | #include "core/hle/service/nfp/nfp_types.h" |
| 13 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 14 | #include "core/hle/service/time/clock_types.h" | ||
| 15 | 14 | ||
| 16 | namespace Kernel { | 15 | namespace Kernel { |
| 17 | class KEvent; | 16 | class KEvent; |
| @@ -49,8 +48,8 @@ public: | |||
| 49 | 48 | ||
| 50 | Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); | 49 | Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); |
| 51 | 50 | ||
| 52 | Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, | 51 | Result SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data, |
| 53 | std::span<const u8> command_data, std::span<u8> out_data); | 52 | std::span<u8> out_data); |
| 54 | 53 | ||
| 55 | Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target); | 54 | Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target); |
| 56 | Result Unmount(); | 55 | Result Unmount(); |
| @@ -108,7 +107,7 @@ private: | |||
| 108 | NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; | 107 | NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; |
| 109 | void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const; | 108 | void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const; |
| 110 | NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const; | 109 | NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const; |
| 111 | u64 GetCurrentPosixTime() const; | 110 | s64 GetCurrentPosixTime() const; |
| 112 | u64 RemoveVersionByte(u64 application_id) const; | 111 | u64 RemoveVersionByte(u64 application_id) const; |
| 113 | void UpdateSettingsCrc(); | 112 | void UpdateSettingsCrc(); |
| 114 | void UpdateRegisterInfoCrc(); | 113 | void UpdateRegisterInfoCrc(); |
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index 44f651b87..b60699c45 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp | |||
| @@ -6,12 +6,14 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/kernel/k_event.h" | 8 | #include "core/hle/kernel/k_event.h" |
| 9 | #include "core/hle/service/glue/time/static.h" | ||
| 9 | #include "core/hle/service/ipc_helpers.h" | 10 | #include "core/hle/service/ipc_helpers.h" |
| 10 | #include "core/hle/service/nfc/common/device.h" | 11 | #include "core/hle/service/nfc/common/device.h" |
| 11 | #include "core/hle/service/nfc/common/device_manager.h" | 12 | #include "core/hle/service/nfc/common/device_manager.h" |
| 12 | #include "core/hle/service/nfc/nfc_result.h" | 13 | #include "core/hle/service/nfc/nfc_result.h" |
| 13 | #include "core/hle/service/time/clock_types.h" | 14 | #include "core/hle/service/psc/time/steady_clock.h" |
| 14 | #include "core/hle/service/time/time_manager.h" | 15 | #include "core/hle/service/service.h" |
| 16 | #include "core/hle/service/sm/sm.h" | ||
| 15 | #include "hid_core/hid_types.h" | 17 | #include "hid_core/hid_types.h" |
| 16 | #include "hid_core/hid_util.h" | 18 | #include "hid_core/hid_util.h" |
| 17 | 19 | ||
| @@ -82,11 +84,19 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max | |||
| 82 | continue; | 84 | continue; |
| 83 | } | 85 | } |
| 84 | if (skip_fatal_errors) { | 86 | if (skip_fatal_errors) { |
| 85 | constexpr u64 MinimumRecoveryTime = 60; | 87 | constexpr s64 MinimumRecoveryTime = 60; |
| 86 | auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; | ||
| 87 | const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point - | ||
| 88 | time_since_last_error; | ||
| 89 | 88 | ||
| 89 | auto static_service = | ||
| 90 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", | ||
| 91 | true); | ||
| 92 | |||
| 93 | std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; | ||
| 94 | static_service->GetStandardSteadyClock(steady_clock); | ||
| 95 | |||
| 96 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 97 | R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); | ||
| 98 | |||
| 99 | const s64 elapsed_time = time_point.time_point - time_since_last_error; | ||
| 90 | if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { | 100 | if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { |
| 91 | continue; | 101 | continue; |
| 92 | } | 102 | } |
| @@ -250,8 +260,7 @@ Result DeviceManager::WriteMifare(u64 device_handle, | |||
| 250 | return result; | 260 | return result; |
| 251 | } | 261 | } |
| 252 | 262 | ||
| 253 | Result DeviceManager::SendCommandByPassThrough(u64 device_handle, | 263 | Result DeviceManager::SendCommandByPassThrough(u64 device_handle, const s64& timeout, |
| 254 | const Time::Clock::TimeSpanType& timeout, | ||
| 255 | std::span<const u8> command_data, | 264 | std::span<const u8> command_data, |
| 256 | std::span<u8> out_data) { | 265 | std::span<u8> out_data) { |
| 257 | std::scoped_lock lock{mutex}; | 266 | std::scoped_lock lock{mutex}; |
| @@ -741,8 +750,16 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, | |||
| 741 | 750 | ||
| 742 | if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 || | 751 | if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 || |
| 743 | operation_result == ResultUnknown115) { | 752 | operation_result == ResultUnknown115) { |
| 744 | auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; | 753 | auto static_service = |
| 745 | time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point; | 754 | system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); |
| 755 | |||
| 756 | std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; | ||
| 757 | static_service->GetStandardSteadyClock(steady_clock); | ||
| 758 | |||
| 759 | Service::PSC::Time::SteadyClockTimePoint time_point{}; | ||
| 760 | R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); | ||
| 761 | |||
| 762 | time_since_last_error = time_point.time_point; | ||
| 746 | } | 763 | } |
| 747 | 764 | ||
| 748 | return operation_result; | 765 | return operation_result; |
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h index f02bdccf5..c56a2fbda 100644 --- a/src/core/hle/service/nfc/common/device_manager.h +++ b/src/core/hle/service/nfc/common/device_manager.h | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include "core/hle/service/nfc/nfc_types.h" | 13 | #include "core/hle/service/nfc/nfc_types.h" |
| 14 | #include "core/hle/service/nfp/nfp_types.h" | 14 | #include "core/hle/service/nfp/nfp_types.h" |
| 15 | #include "core/hle/service/service.h" | 15 | #include "core/hle/service/service.h" |
| 16 | #include "core/hle/service/time/clock_types.h" | ||
| 17 | #include "hid_core/hid_types.h" | 16 | #include "hid_core/hid_types.h" |
| 18 | 17 | ||
| 19 | namespace Service::NFC { | 18 | namespace Service::NFC { |
| @@ -42,7 +41,7 @@ public: | |||
| 42 | std::span<MifareReadBlockData> read_data); | 41 | std::span<MifareReadBlockData> read_data); |
| 43 | Result WriteMifare(u64 device_handle, | 42 | Result WriteMifare(u64 device_handle, |
| 44 | std::span<const MifareWriteBlockParameter> write_parameters); | 43 | std::span<const MifareWriteBlockParameter> write_parameters); |
| 45 | Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout, | 44 | Result SendCommandByPassThrough(u64 device_handle, const s64& timeout, |
| 46 | std::span<const u8> command_data, std::span<u8> out_data); | 45 | std::span<const u8> command_data, std::span<u8> out_data); |
| 47 | 46 | ||
| 48 | // Nfp device manager | 47 | // Nfp device manager |
| @@ -92,7 +91,7 @@ private: | |||
| 92 | const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; | 91 | const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; |
| 93 | 92 | ||
| 94 | bool is_initialized = false; | 93 | bool is_initialized = false; |
| 95 | u64 time_since_last_error = 0; | 94 | s64 time_since_last_error = 0; |
| 96 | mutable std::mutex mutex; | 95 | mutable std::mutex mutex; |
| 97 | std::array<std::shared_ptr<NfcDevice>, 10> devices{}; | 96 | std::array<std::shared_ptr<NfcDevice>, 10> devices{}; |
| 98 | 97 | ||
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index a71cf74b8..207ac4efe 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include "core/hle/service/nfc/nfc_result.h" | 13 | #include "core/hle/service/nfc/nfc_result.h" |
| 14 | #include "core/hle/service/nfc/nfc_types.h" | 14 | #include "core/hle/service/nfc/nfc_types.h" |
| 15 | #include "core/hle/service/nfp/nfp_result.h" | 15 | #include "core/hle/service/nfp/nfp_result.h" |
| 16 | #include "core/hle/service/time/clock_types.h" | ||
| 17 | #include "hid_core/hid_types.h" | 16 | #include "hid_core/hid_types.h" |
| 18 | 17 | ||
| 19 | namespace Service::NFC { | 18 | namespace Service::NFC { |
| @@ -261,10 +260,10 @@ void NfcInterface::WriteMifare(HLERequestContext& ctx) { | |||
| 261 | void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) { | 260 | void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) { |
| 262 | IPC::RequestParser rp{ctx}; | 261 | IPC::RequestParser rp{ctx}; |
| 263 | const auto device_handle{rp.Pop<u64>()}; | 262 | const auto device_handle{rp.Pop<u64>()}; |
| 264 | const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()}; | 263 | const auto timeout{rp.PopRaw<s64>()}; |
| 265 | const auto command_data{ctx.ReadBuffer()}; | 264 | const auto command_data{ctx.ReadBuffer()}; |
| 266 | LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", | 265 | LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", |
| 267 | device_handle, timeout.ToSeconds(), command_data.size()); | 266 | device_handle, timeout, command_data.size()); |
| 268 | 267 | ||
| 269 | std::vector<u8> out_data(1); | 268 | std::vector<u8> out_data(1); |
| 270 | auto result = | 269 | auto result = |
diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp index b1a7686ff..d187be935 100644 --- a/src/core/hle/service/ns/language.cpp +++ b/src/core/hle/service/ns/language.cpp | |||
| @@ -415,4 +415,4 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage | |||
| 415 | return std::nullopt; | 415 | return std::nullopt; |
| 416 | } | 416 | } |
| 417 | } | 417 | } |
| 418 | } // namespace Service::NS \ No newline at end of file | 418 | } // namespace Service::NS |
diff --git a/src/core/hle/service/ns/language.h b/src/core/hle/service/ns/language.h index ab6b71029..dad9934f2 100644 --- a/src/core/hle/service/ns/language.h +++ b/src/core/hle/service/ns/language.h | |||
| @@ -5,10 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <optional> | 6 | #include <optional> |
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | 8 | #include "core/hle/service/set/system_settings_server.h" | |
| 9 | namespace Service::Set { | ||
| 10 | enum class LanguageCode : u64; | ||
| 11 | } | ||
| 12 | 9 | ||
| 13 | namespace Service::NS { | 10 | namespace Service::NS { |
| 14 | /// This is nn::ns::detail::ApplicationLanguage | 11 | /// This is nn::ns::detail::ApplicationLanguage |
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index cd0cc9287..44310756b 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp | |||
| @@ -4,9 +4,13 @@ | |||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | 5 | ||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/service/ipc_helpers.h" | 8 | #include "core/hle/service/ipc_helpers.h" |
| 8 | #include "core/hle/service/psc/psc.h" | 9 | #include "core/hle/service/psc/psc.h" |
| 9 | #include "core/hle/service/server_manager.h" | 10 | #include "core/hle/service/psc/time/manager.h" |
| 11 | #include "core/hle/service/psc/time/power_state_service.h" | ||
| 12 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 13 | #include "core/hle/service/psc/time/static.h" | ||
| 10 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| 11 | 15 | ||
| 12 | namespace Service::PSC { | 16 | namespace Service::PSC { |
| @@ -76,6 +80,17 @@ void LoopProcess(Core::System& system) { | |||
| 76 | 80 | ||
| 77 | server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); | 81 | server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); |
| 78 | server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); | 82 | server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); |
| 83 | |||
| 84 | auto time = std::make_shared<Time::TimeManager>(system); | ||
| 85 | |||
| 86 | server_manager->RegisterNamedService( | ||
| 87 | "time:m", std::make_shared<Time::ServiceManager>(system, time, server_manager.get())); | ||
| 88 | server_manager->RegisterNamedService( | ||
| 89 | "time:su", std::make_shared<Time::StaticService>( | ||
| 90 | system, Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 1}, time, "time:su")); | ||
| 91 | server_manager->RegisterNamedService("time:al", | ||
| 92 | std::make_shared<Time::IAlarmService>(system, time)); | ||
| 93 | |||
| 79 | ServerManager::RunServer(std::move(server_manager)); | 94 | ServerManager::RunServer(std::move(server_manager)); |
| 80 | } | 95 | } |
| 81 | 96 | ||
diff --git a/src/core/hle/service/psc/time/alarms.cpp b/src/core/hle/service/psc/time/alarms.cpp new file mode 100644 index 000000000..5e52c19f8 --- /dev/null +++ b/src/core/hle/service/psc/time/alarms.cpp | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/alarms.h" | ||
| 6 | #include "core/hle/service/psc/time/manager.h" | ||
| 7 | |||
| 8 | namespace Service::PSC::Time { | ||
| 9 | Alarm::Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type) | ||
| 10 | : m_ctx{ctx}, m_event{ctx.CreateEvent("Psc:Alarm:Event")} { | ||
| 11 | m_event->Clear(); | ||
| 12 | |||
| 13 | switch (type) { | ||
| 14 | case WakeupAlarm: | ||
| 15 | m_priority = 1; | ||
| 16 | break; | ||
| 17 | case BackgroundTaskAlarm: | ||
| 18 | m_priority = 0; | ||
| 19 | break; | ||
| 20 | default: | ||
| 21 | UNREACHABLE(); | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | Alarm::~Alarm() { | ||
| 27 | m_ctx.CloseEvent(m_event); | ||
| 28 | } | ||
| 29 | |||
| 30 | Alarms::Alarms(Core::System& system, StandardSteadyClockCore& steady_clock, | ||
| 31 | PowerStateRequestManager& power_state_request_manager) | ||
| 32 | : m_system{system}, m_ctx{system, "Psc:Alarms"}, m_steady_clock{steady_clock}, | ||
| 33 | m_power_state_request_manager{power_state_request_manager}, m_event{m_ctx.CreateEvent( | ||
| 34 | "Psc:Alarms:Event")} {} | ||
| 35 | |||
| 36 | Alarms::~Alarms() { | ||
| 37 | m_ctx.CloseEvent(m_event); | ||
| 38 | } | ||
| 39 | |||
| 40 | Result Alarms::Enable(Alarm& alarm, s64 time) { | ||
| 41 | R_UNLESS(m_steady_clock.IsInitialized(), ResultClockUninitialized); | ||
| 42 | |||
| 43 | std::scoped_lock l{m_mutex}; | ||
| 44 | R_UNLESS(alarm.IsLinked(), ResultAlarmNotRegistered); | ||
| 45 | |||
| 46 | auto time_ns{time + m_steady_clock.GetRawTime()}; | ||
| 47 | auto one_second_ns{ | ||
| 48 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 49 | time_ns = Common::AlignUp(time_ns, one_second_ns); | ||
| 50 | alarm.SetAlertTime(time_ns); | ||
| 51 | |||
| 52 | Insert(alarm); | ||
| 53 | R_RETURN(UpdateClosestAndSignal()); | ||
| 54 | } | ||
| 55 | |||
| 56 | void Alarms::Disable(Alarm& alarm) { | ||
| 57 | std::scoped_lock l{m_mutex}; | ||
| 58 | if (!alarm.IsLinked()) { | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | |||
| 62 | Erase(alarm); | ||
| 63 | UpdateClosestAndSignal(); | ||
| 64 | } | ||
| 65 | |||
| 66 | void Alarms::CheckAndSignal() { | ||
| 67 | std::scoped_lock l{m_mutex}; | ||
| 68 | if (m_alarms.empty()) { | ||
| 69 | return; | ||
| 70 | } | ||
| 71 | |||
| 72 | bool alarm_signalled{false}; | ||
| 73 | for (auto& alarm : m_alarms) { | ||
| 74 | if (m_steady_clock.GetRawTime() >= alarm.GetAlertTime()) { | ||
| 75 | alarm.Signal(); | ||
| 76 | alarm.Lock(); | ||
| 77 | Erase(alarm); | ||
| 78 | |||
| 79 | m_power_state_request_manager.UpdatePendingPowerStateRequestPriority( | ||
| 80 | alarm.GetPriority()); | ||
| 81 | alarm_signalled = true; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | if (!alarm_signalled) { | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | m_power_state_request_manager.SignalPowerStateRequestAvailability(); | ||
| 90 | UpdateClosestAndSignal(); | ||
| 91 | } | ||
| 92 | |||
| 93 | bool Alarms::GetClosestAlarm(Alarm** out_alarm) { | ||
| 94 | std::scoped_lock l{m_mutex}; | ||
| 95 | auto alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front()); | ||
| 96 | *out_alarm = alarm; | ||
| 97 | return alarm != nullptr; | ||
| 98 | } | ||
| 99 | |||
| 100 | void Alarms::Insert(Alarm& alarm) { | ||
| 101 | // Alarms are sorted by alert time, then priority | ||
| 102 | auto it{m_alarms.begin()}; | ||
| 103 | while (it != m_alarms.end()) { | ||
| 104 | if (alarm.GetAlertTime() < it->GetAlertTime() || | ||
| 105 | (alarm.GetAlertTime() == it->GetAlertTime() && | ||
| 106 | alarm.GetPriority() < it->GetPriority())) { | ||
| 107 | m_alarms.insert(it, alarm); | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | it++; | ||
| 111 | } | ||
| 112 | |||
| 113 | m_alarms.push_back(alarm); | ||
| 114 | } | ||
| 115 | |||
| 116 | void Alarms::Erase(Alarm& alarm) { | ||
| 117 | m_alarms.erase(m_alarms.iterator_to(alarm)); | ||
| 118 | } | ||
| 119 | |||
| 120 | Result Alarms::UpdateClosestAndSignal() { | ||
| 121 | m_closest_alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front()); | ||
| 122 | R_SUCCEED_IF(m_closest_alarm == nullptr); | ||
| 123 | |||
| 124 | m_event->Signal(); | ||
| 125 | |||
| 126 | R_SUCCEED(); | ||
| 127 | } | ||
| 128 | |||
| 129 | IAlarmService::IAlarmService(Core::System& system_, std::shared_ptr<TimeManager> manager) | ||
| 130 | : ServiceFramework{system_, "time:al"}, m_system{system}, m_alarms{manager->m_alarms} { | ||
| 131 | // clang-format off | ||
| 132 | static const FunctionInfo functions[] = { | ||
| 133 | {0, &IAlarmService::CreateWakeupAlarm, "CreateWakeupAlarm"}, | ||
| 134 | {1, &IAlarmService::CreateBackgroundTaskAlarm, "CreateBackgroundTaskAlarm"}, | ||
| 135 | }; | ||
| 136 | // clang-format on | ||
| 137 | RegisterHandlers(functions); | ||
| 138 | } | ||
| 139 | |||
| 140 | void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) { | ||
| 141 | LOG_DEBUG(Service_Time, "called."); | ||
| 142 | |||
| 143 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 144 | rb.Push(ResultSuccess); | ||
| 145 | rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm); | ||
| 146 | } | ||
| 147 | |||
| 148 | void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) { | ||
| 149 | LOG_DEBUG(Service_Time, "called."); | ||
| 150 | |||
| 151 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 152 | rb.Push(ResultSuccess); | ||
| 153 | rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm); | ||
| 154 | } | ||
| 155 | |||
| 156 | ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type) | ||
| 157 | : ServiceFramework{system_, "ISteadyClockAlarm"}, m_ctx{system, "Psc:ISteadyClockAlarm"}, | ||
| 158 | m_alarms{alarms}, m_alarm{system, m_ctx, type} { | ||
| 159 | // clang-format off | ||
| 160 | static const FunctionInfo functions[] = { | ||
| 161 | {0, &ISteadyClockAlarm::GetAlarmEvent, "GetAlarmEvent"}, | ||
| 162 | {1, &ISteadyClockAlarm::Enable, "Enable"}, | ||
| 163 | {2, &ISteadyClockAlarm::Disable, "Disable"}, | ||
| 164 | {3, &ISteadyClockAlarm::IsEnabled, "IsEnabled"}, | ||
| 165 | {10, nullptr, "CreateWakeLock"}, | ||
| 166 | {11, nullptr, "DestroyWakeLock"}, | ||
| 167 | }; | ||
| 168 | // clang-format on | ||
| 169 | RegisterHandlers(functions); | ||
| 170 | } | ||
| 171 | |||
| 172 | void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) { | ||
| 173 | LOG_DEBUG(Service_Time, "called."); | ||
| 174 | |||
| 175 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 176 | rb.Push(ResultSuccess); | ||
| 177 | rb.PushCopyObjects(m_alarm.GetEventHandle()); | ||
| 178 | } | ||
| 179 | |||
| 180 | void ISteadyClockAlarm::Enable(HLERequestContext& ctx) { | ||
| 181 | LOG_DEBUG(Service_Time, "called."); | ||
| 182 | |||
| 183 | IPC::RequestParser rp{ctx}; | ||
| 184 | auto time{rp.Pop<s64>()}; | ||
| 185 | |||
| 186 | auto res = m_alarms.Enable(m_alarm, time); | ||
| 187 | |||
| 188 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 189 | rb.Push(res); | ||
| 190 | } | ||
| 191 | |||
| 192 | void ISteadyClockAlarm::Disable(HLERequestContext& ctx) { | ||
| 193 | LOG_DEBUG(Service_Time, "called."); | ||
| 194 | |||
| 195 | m_alarms.Disable(m_alarm); | ||
| 196 | |||
| 197 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 198 | rb.Push(ResultSuccess); | ||
| 199 | } | ||
| 200 | |||
| 201 | void ISteadyClockAlarm::IsEnabled(HLERequestContext& ctx) { | ||
| 202 | LOG_DEBUG(Service_Time, "called."); | ||
| 203 | |||
| 204 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 205 | rb.Push(ResultSuccess); | ||
| 206 | rb.Push<bool>(m_alarm.IsLinked()); | ||
| 207 | } | ||
| 208 | |||
| 209 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/alarms.h b/src/core/hle/service/psc/time/alarms.h new file mode 100644 index 000000000..597770028 --- /dev/null +++ b/src/core/hle/service/psc/time/alarms.h | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "core/hle/kernel/k_event.h" | ||
| 9 | #include "core/hle/service/ipc_helpers.h" | ||
| 10 | #include "core/hle/service/kernel_helpers.h" | ||
| 11 | #include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h" | ||
| 12 | #include "core/hle/service/psc/time/common.h" | ||
| 13 | #include "core/hle/service/psc/time/power_state_request_manager.h" | ||
| 14 | #include "core/hle/service/server_manager.h" | ||
| 15 | #include "core/hle/service/service.h" | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Service::PSC::Time { | ||
| 22 | class TimeManager; | ||
| 23 | |||
| 24 | enum AlarmType : u32 { | ||
| 25 | WakeupAlarm = 0, | ||
| 26 | BackgroundTaskAlarm = 1, | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct Alarm : public Common::IntrusiveListBaseNode<Alarm> { | ||
| 30 | using AlarmList = Common::IntrusiveListBaseTraits<Alarm>::ListType; | ||
| 31 | |||
| 32 | Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type); | ||
| 33 | ~Alarm(); | ||
| 34 | |||
| 35 | Kernel::KReadableEvent& GetEventHandle() { | ||
| 36 | return m_event->GetReadableEvent(); | ||
| 37 | } | ||
| 38 | |||
| 39 | s64 GetAlertTime() const { | ||
| 40 | return m_alert_time; | ||
| 41 | } | ||
| 42 | |||
| 43 | void SetAlertTime(s64 time) { | ||
| 44 | m_alert_time = time; | ||
| 45 | } | ||
| 46 | |||
| 47 | u32 GetPriority() const { | ||
| 48 | return m_priority; | ||
| 49 | } | ||
| 50 | |||
| 51 | void Signal() { | ||
| 52 | m_event->Signal(); | ||
| 53 | } | ||
| 54 | |||
| 55 | Result Lock() { | ||
| 56 | // TODO | ||
| 57 | // if (m_lock_service) { | ||
| 58 | // return m_lock_service->Lock(); | ||
| 59 | // } | ||
| 60 | R_SUCCEED(); | ||
| 61 | } | ||
| 62 | |||
| 63 | KernelHelpers::ServiceContext& m_ctx; | ||
| 64 | |||
| 65 | u32 m_priority; | ||
| 66 | Kernel::KEvent* m_event{}; | ||
| 67 | s64 m_alert_time{}; | ||
| 68 | // TODO | ||
| 69 | // nn::psc::sf::IPmStateLock* m_lock_service{}; | ||
| 70 | }; | ||
| 71 | |||
| 72 | class Alarms { | ||
| 73 | public: | ||
| 74 | explicit Alarms(Core::System& system, StandardSteadyClockCore& steady_clock, | ||
| 75 | PowerStateRequestManager& power_state_request_manager); | ||
| 76 | ~Alarms(); | ||
| 77 | |||
| 78 | Kernel::KEvent& GetEvent() { | ||
| 79 | return *m_event; | ||
| 80 | } | ||
| 81 | |||
| 82 | s64 GetRawTime() { | ||
| 83 | return m_steady_clock.GetRawTime(); | ||
| 84 | } | ||
| 85 | |||
| 86 | Result Enable(Alarm& alarm, s64 time); | ||
| 87 | void Disable(Alarm& alarm); | ||
| 88 | void CheckAndSignal(); | ||
| 89 | bool GetClosestAlarm(Alarm** out_alarm); | ||
| 90 | |||
| 91 | private: | ||
| 92 | void Insert(Alarm& alarm); | ||
| 93 | void Erase(Alarm& alarm); | ||
| 94 | Result UpdateClosestAndSignal(); | ||
| 95 | |||
| 96 | Core::System& m_system; | ||
| 97 | KernelHelpers::ServiceContext m_ctx; | ||
| 98 | |||
| 99 | StandardSteadyClockCore& m_steady_clock; | ||
| 100 | PowerStateRequestManager& m_power_state_request_manager; | ||
| 101 | Alarm::AlarmList m_alarms; | ||
| 102 | Kernel::KEvent* m_event{}; | ||
| 103 | Alarm* m_closest_alarm{}; | ||
| 104 | std::mutex m_mutex; | ||
| 105 | }; | ||
| 106 | |||
| 107 | class IAlarmService final : public ServiceFramework<IAlarmService> { | ||
| 108 | public: | ||
| 109 | explicit IAlarmService(Core::System& system, std::shared_ptr<TimeManager> manager); | ||
| 110 | |||
| 111 | ~IAlarmService() override = default; | ||
| 112 | |||
| 113 | private: | ||
| 114 | void CreateWakeupAlarm(HLERequestContext& ctx); | ||
| 115 | void CreateBackgroundTaskAlarm(HLERequestContext& ctx); | ||
| 116 | |||
| 117 | Core::System& m_system; | ||
| 118 | Alarms& m_alarms; | ||
| 119 | }; | ||
| 120 | |||
| 121 | class ISteadyClockAlarm final : public ServiceFramework<ISteadyClockAlarm> { | ||
| 122 | public: | ||
| 123 | explicit ISteadyClockAlarm(Core::System& system, Alarms& alarms, AlarmType type); | ||
| 124 | |||
| 125 | ~ISteadyClockAlarm() override = default; | ||
| 126 | |||
| 127 | private: | ||
| 128 | void GetAlarmEvent(HLERequestContext& ctx); | ||
| 129 | void Enable(HLERequestContext& ctx); | ||
| 130 | void Disable(HLERequestContext& ctx); | ||
| 131 | void IsEnabled(HLERequestContext& ctx); | ||
| 132 | |||
| 133 | KernelHelpers::ServiceContext m_ctx; | ||
| 134 | |||
| 135 | Alarms& m_alarms; | ||
| 136 | Alarm m_alarm; | ||
| 137 | }; | ||
| 138 | |||
| 139 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/context_writers.cpp b/src/core/hle/service/psc/time/clocks/context_writers.cpp new file mode 100644 index 000000000..ac8700f76 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/context_writers.cpp | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | |||
| 9 | void ContextWriter::SignalAllNodes() { | ||
| 10 | std::scoped_lock l{m_mutex}; | ||
| 11 | for (auto& operation : m_operation_events) { | ||
| 12 | operation.m_event->Signal(); | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | void ContextWriter::Link(OperationEvent& operation_event) { | ||
| 17 | std::scoped_lock l{m_mutex}; | ||
| 18 | m_operation_events.push_back(operation_event); | ||
| 19 | } | ||
| 20 | |||
| 21 | LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& system, | ||
| 22 | SharedMemory& shared_memory) | ||
| 23 | : m_system{system}, m_shared_memory{shared_memory} {} | ||
| 24 | |||
| 25 | Result LocalSystemClockContextWriter::Write(SystemClockContext& context) { | ||
| 26 | if (m_in_use) { | ||
| 27 | R_SUCCEED_IF(context == m_context); | ||
| 28 | m_context = context; | ||
| 29 | } else { | ||
| 30 | m_context = context; | ||
| 31 | m_in_use = true; | ||
| 32 | } | ||
| 33 | |||
| 34 | m_shared_memory.SetLocalSystemContext(context); | ||
| 35 | |||
| 36 | SignalAllNodes(); | ||
| 37 | |||
| 38 | R_SUCCEED(); | ||
| 39 | } | ||
| 40 | |||
| 41 | NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& system, | ||
| 42 | SharedMemory& shared_memory, | ||
| 43 | SystemClockCore& system_clock) | ||
| 44 | : m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {} | ||
| 45 | |||
| 46 | Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) { | ||
| 47 | s64 time{}; | ||
| 48 | [[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time); | ||
| 49 | |||
| 50 | if (m_in_use) { | ||
| 51 | R_SUCCEED_IF(context == m_context); | ||
| 52 | m_context = context; | ||
| 53 | } else { | ||
| 54 | m_context = context; | ||
| 55 | m_in_use = true; | ||
| 56 | } | ||
| 57 | |||
| 58 | m_shared_memory.SetNetworkSystemContext(context); | ||
| 59 | |||
| 60 | SignalAllNodes(); | ||
| 61 | |||
| 62 | R_SUCCEED(); | ||
| 63 | } | ||
| 64 | |||
| 65 | EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWriter( | ||
| 66 | Core::System& system) | ||
| 67 | : m_system{system} {} | ||
| 68 | |||
| 69 | Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) { | ||
| 70 | if (m_in_use) { | ||
| 71 | R_SUCCEED_IF(context == m_context); | ||
| 72 | m_context = context; | ||
| 73 | } else { | ||
| 74 | m_context = context; | ||
| 75 | m_in_use = true; | ||
| 76 | } | ||
| 77 | |||
| 78 | SignalAllNodes(); | ||
| 79 | |||
| 80 | R_SUCCEED(); | ||
| 81 | } | ||
| 82 | |||
| 83 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/context_writers.h b/src/core/hle/service/psc/time/clocks/context_writers.h new file mode 100644 index 000000000..afd3725d4 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/context_writers.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <list> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/kernel/k_event.h" | ||
| 10 | #include "core/hle/service/psc/time/clocks/system_clock_core.h" | ||
| 11 | #include "core/hle/service/psc/time/common.h" | ||
| 12 | #include "core/hle/service/psc/time/shared_memory.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::PSC::Time { | ||
| 19 | |||
| 20 | class ContextWriter { | ||
| 21 | private: | ||
| 22 | using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType; | ||
| 23 | |||
| 24 | public: | ||
| 25 | virtual ~ContextWriter() = default; | ||
| 26 | |||
| 27 | virtual Result Write(SystemClockContext& context) = 0; | ||
| 28 | void SignalAllNodes(); | ||
| 29 | void Link(OperationEvent& operation_event); | ||
| 30 | |||
| 31 | private: | ||
| 32 | OperationEventList m_operation_events; | ||
| 33 | std::mutex m_mutex; | ||
| 34 | }; | ||
| 35 | |||
| 36 | class LocalSystemClockContextWriter : public ContextWriter { | ||
| 37 | public: | ||
| 38 | explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory); | ||
| 39 | |||
| 40 | Result Write(SystemClockContext& context) override; | ||
| 41 | |||
| 42 | private: | ||
| 43 | Core::System& m_system; | ||
| 44 | |||
| 45 | SharedMemory& m_shared_memory; | ||
| 46 | bool m_in_use{}; | ||
| 47 | SystemClockContext m_context{}; | ||
| 48 | }; | ||
| 49 | |||
| 50 | class NetworkSystemClockContextWriter : public ContextWriter { | ||
| 51 | public: | ||
| 52 | explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory, | ||
| 53 | SystemClockCore& system_clock); | ||
| 54 | |||
| 55 | Result Write(SystemClockContext& context) override; | ||
| 56 | |||
| 57 | private: | ||
| 58 | Core::System& m_system; | ||
| 59 | |||
| 60 | SharedMemory& m_shared_memory; | ||
| 61 | bool m_in_use{}; | ||
| 62 | SystemClockContext m_context{}; | ||
| 63 | SystemClockCore& m_system_clock; | ||
| 64 | }; | ||
| 65 | |||
| 66 | class EphemeralNetworkSystemClockContextWriter : public ContextWriter { | ||
| 67 | public: | ||
| 68 | EphemeralNetworkSystemClockContextWriter(Core::System& system); | ||
| 69 | |||
| 70 | Result Write(SystemClockContext& context) override; | ||
| 71 | |||
| 72 | private: | ||
| 73 | Core::System& m_system; | ||
| 74 | |||
| 75 | bool m_in_use{}; | ||
| 76 | SystemClockContext m_context{}; | ||
| 77 | }; | ||
| 78 | |||
| 79 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h b/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h new file mode 100644 index 000000000..0a68867d9 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 8 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/system_clock_core.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Service::PSC::Time { | ||
| 13 | |||
| 14 | class EphemeralNetworkSystemClockCore : public SystemClockCore { | ||
| 15 | public: | ||
| 16 | explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock) | ||
| 17 | : SystemClockCore{steady_clock} {} | ||
| 18 | ~EphemeralNetworkSystemClockCore() override = default; | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp new file mode 100644 index 000000000..36dca6689 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" | ||
| 5 | |||
| 6 | namespace Service::PSC::Time { | ||
| 7 | |||
| 8 | void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) { | ||
| 9 | SteadyClockTimePoint time_point{}; | ||
| 10 | if (GetCurrentTimePoint(time_point) == ResultSuccess && | ||
| 11 | context.steady_time_point.IdMatches(time_point)) { | ||
| 12 | SetContextAndWrite(context); | ||
| 13 | } else if (SetCurrentTime(time) != ResultSuccess) { | ||
| 14 | LOG_ERROR(Service_Time, "Failed to SetCurrentTime"); | ||
| 15 | } | ||
| 16 | |||
| 17 | SetInitialized(); | ||
| 18 | } | ||
| 19 | |||
| 20 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h new file mode 100644 index 000000000..176ba3e94 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 8 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/system_clock_core.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Service::PSC::Time { | ||
| 13 | |||
| 14 | class StandardLocalSystemClockCore : public SystemClockCore { | ||
| 15 | public: | ||
| 16 | explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock) | ||
| 17 | : SystemClockCore{steady_clock} {} | ||
| 18 | ~StandardLocalSystemClockCore() override = default; | ||
| 19 | |||
| 20 | void Initialize(SystemClockContext& context, s64 time); | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp new file mode 100644 index 000000000..8d6cb7db1 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" | ||
| 5 | |||
| 6 | namespace Service::PSC::Time { | ||
| 7 | |||
| 8 | void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) { | ||
| 9 | if (SetContextAndWrite(context) != ResultSuccess) { | ||
| 10 | LOG_ERROR(Service_Time, "Failed to SetContext"); | ||
| 11 | } | ||
| 12 | m_sufficient_accuracy = accuracy; | ||
| 13 | SetInitialized(); | ||
| 14 | } | ||
| 15 | |||
| 16 | bool StandardNetworkSystemClockCore::IsAccuracySufficient() { | ||
| 17 | if (!IsInitialized()) { | ||
| 18 | return false; | ||
| 19 | } | ||
| 20 | |||
| 21 | SystemClockContext context{}; | ||
| 22 | SteadyClockTimePoint current_time_point{}; | ||
| 23 | if (GetCurrentTimePoint(current_time_point) != ResultSuccess || | ||
| 24 | GetContext(context) != ResultSuccess) { | ||
| 25 | return false; | ||
| 26 | } | ||
| 27 | |||
| 28 | s64 seconds{}; | ||
| 29 | if (GetSpanBetweenTimePoints(&seconds, context.steady_time_point, current_time_point) != | ||
| 30 | ResultSuccess) { | ||
| 31 | return false; | ||
| 32 | } | ||
| 33 | |||
| 34 | if (std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(seconds)) | ||
| 35 | .count() < m_sufficient_accuracy) { | ||
| 36 | return true; | ||
| 37 | } | ||
| 38 | |||
| 39 | return false; | ||
| 40 | } | ||
| 41 | |||
| 42 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h new file mode 100644 index 000000000..933d2c8e3 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 10 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 11 | #include "core/hle/service/psc/time/clocks/system_clock_core.h" | ||
| 12 | #include "core/hle/service/psc/time/common.h" | ||
| 13 | |||
| 14 | namespace Service::PSC::Time { | ||
| 15 | |||
| 16 | class StandardNetworkSystemClockCore : public SystemClockCore { | ||
| 17 | public: | ||
| 18 | explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock) | ||
| 19 | : SystemClockCore{steady_clock} {} | ||
| 20 | ~StandardNetworkSystemClockCore() override = default; | ||
| 21 | |||
| 22 | void Initialize(SystemClockContext& context, s64 accuracy); | ||
| 23 | bool IsAccuracySufficient(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | s64 m_sufficient_accuracy{ | ||
| 27 | std::chrono ::duration_cast<std::chrono::nanoseconds>(std::chrono::days(10)).count()}; | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp new file mode 100644 index 000000000..7a72d7aa2 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | #include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Service::PSC::Time { | ||
| 11 | |||
| 12 | void StandardSteadyClockCore::Initialize(ClockSourceId clock_source_id, s64 rtc_offset, | ||
| 13 | s64 internal_offset, s64 test_offset, | ||
| 14 | bool is_rtc_reset_detected) { | ||
| 15 | m_clock_source_id = clock_source_id; | ||
| 16 | m_rtc_offset = rtc_offset; | ||
| 17 | m_internal_offset = internal_offset; | ||
| 18 | m_test_offset = test_offset; | ||
| 19 | if (is_rtc_reset_detected) { | ||
| 20 | SetResetDetected(); | ||
| 21 | } | ||
| 22 | SetInitialized(); | ||
| 23 | } | ||
| 24 | |||
| 25 | void StandardSteadyClockCore::SetRtcOffset(s64 offset) { | ||
| 26 | m_rtc_offset = offset; | ||
| 27 | } | ||
| 28 | |||
| 29 | void StandardSteadyClockCore::SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time) { | ||
| 30 | auto ticks{m_system.CoreTiming().GetClockTicks()}; | ||
| 31 | |||
| 32 | m_continuous_adjustment_time_point.rtc_offset = ConvertToTimeSpan(ticks).count(); | ||
| 33 | m_continuous_adjustment_time_point.diff_scale = 0; | ||
| 34 | m_continuous_adjustment_time_point.shift_amount = 0; | ||
| 35 | m_continuous_adjustment_time_point.lower = time; | ||
| 36 | m_continuous_adjustment_time_point.upper = time; | ||
| 37 | m_continuous_adjustment_time_point.clock_source_id = clock_source_id; | ||
| 38 | } | ||
| 39 | |||
| 40 | void StandardSteadyClockCore::GetContinuousAdjustment( | ||
| 41 | ContinuousAdjustmentTimePoint& out_time_point) const { | ||
| 42 | out_time_point = m_continuous_adjustment_time_point; | ||
| 43 | } | ||
| 44 | |||
| 45 | void StandardSteadyClockCore::UpdateContinuousAdjustmentTime(s64 in_time) { | ||
| 46 | auto ticks{m_system.CoreTiming().GetClockTicks()}; | ||
| 47 | auto uptime_ns{ConvertToTimeSpan(ticks).count()}; | ||
| 48 | auto adjusted_time{((uptime_ns - m_continuous_adjustment_time_point.rtc_offset) * | ||
| 49 | m_continuous_adjustment_time_point.diff_scale) >> | ||
| 50 | m_continuous_adjustment_time_point.shift_amount}; | ||
| 51 | auto expected_time{adjusted_time + m_continuous_adjustment_time_point.lower}; | ||
| 52 | |||
| 53 | auto last_time_point{m_continuous_adjustment_time_point.upper}; | ||
| 54 | m_continuous_adjustment_time_point.upper = in_time; | ||
| 55 | auto t1{std::min<s64>(expected_time, last_time_point)}; | ||
| 56 | expected_time = std::max<s64>(expected_time, last_time_point); | ||
| 57 | expected_time = m_continuous_adjustment_time_point.diff_scale >= 0 ? t1 : expected_time; | ||
| 58 | |||
| 59 | auto new_diff{in_time < expected_time ? -55 : 55}; | ||
| 60 | |||
| 61 | m_continuous_adjustment_time_point.rtc_offset = uptime_ns; | ||
| 62 | m_continuous_adjustment_time_point.shift_amount = expected_time == in_time ? 0 : 14; | ||
| 63 | m_continuous_adjustment_time_point.diff_scale = expected_time == in_time ? 0 : new_diff; | ||
| 64 | m_continuous_adjustment_time_point.lower = expected_time; | ||
| 65 | } | ||
| 66 | |||
| 67 | Result StandardSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) { | ||
| 68 | auto current_time_ns = GetCurrentRawTimePointImpl(); | ||
| 69 | auto current_time_s = | ||
| 70 | std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds(current_time_ns)); | ||
| 71 | out_time_point.time_point = current_time_s.count(); | ||
| 72 | out_time_point.clock_source_id = m_clock_source_id; | ||
| 73 | R_SUCCEED(); | ||
| 74 | } | ||
| 75 | |||
| 76 | s64 StandardSteadyClockCore::GetCurrentRawTimePointImpl() { | ||
| 77 | std::scoped_lock l{m_mutex}; | ||
| 78 | auto ticks{static_cast<s64>(m_system.CoreTiming().GetClockTicks())}; | ||
| 79 | auto current_time_ns = m_rtc_offset + ConvertToTimeSpan(ticks).count(); | ||
| 80 | auto time_point = std::max<s64>(current_time_ns, m_cached_time_point); | ||
| 81 | m_cached_time_point = time_point; | ||
| 82 | return time_point; | ||
| 83 | } | ||
| 84 | |||
| 85 | s64 StandardSteadyClockCore::GetTestOffsetImpl() const { | ||
| 86 | return m_test_offset; | ||
| 87 | } | ||
| 88 | |||
| 89 | void StandardSteadyClockCore::SetTestOffsetImpl(s64 offset) { | ||
| 90 | m_test_offset = offset; | ||
| 91 | } | ||
| 92 | |||
| 93 | s64 StandardSteadyClockCore::GetInternalOffsetImpl() const { | ||
| 94 | return m_internal_offset; | ||
| 95 | } | ||
| 96 | |||
| 97 | void StandardSteadyClockCore::SetInternalOffsetImpl(s64 offset) { | ||
| 98 | m_internal_offset = offset; | ||
| 99 | } | ||
| 100 | |||
| 101 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h new file mode 100644 index 000000000..bbf98fcd5 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::PSC::Time { | ||
| 15 | class StandardSteadyClockCore : public SteadyClockCore { | ||
| 16 | public: | ||
| 17 | explicit StandardSteadyClockCore(Core::System& system) : m_system{system} {} | ||
| 18 | ~StandardSteadyClockCore() override = default; | ||
| 19 | |||
| 20 | void Initialize(ClockSourceId clock_source_id, s64 rtc_offset, s64 internal_offset, | ||
| 21 | s64 test_offset, bool is_rtc_reset_detected); | ||
| 22 | |||
| 23 | void SetRtcOffset(s64 offset); | ||
| 24 | void SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time); | ||
| 25 | void GetContinuousAdjustment(ContinuousAdjustmentTimePoint& out_time_point) const; | ||
| 26 | void UpdateContinuousAdjustmentTime(s64 time); | ||
| 27 | |||
| 28 | Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override; | ||
| 29 | s64 GetCurrentRawTimePointImpl() override; | ||
| 30 | s64 GetTestOffsetImpl() const override; | ||
| 31 | void SetTestOffsetImpl(s64 offset) override; | ||
| 32 | s64 GetInternalOffsetImpl() const override; | ||
| 33 | void SetInternalOffsetImpl(s64 offset) override; | ||
| 34 | |||
| 35 | Result GetRtcValueImpl(s64& out_value) override { | ||
| 36 | R_RETURN(ResultNotImplemented); | ||
| 37 | } | ||
| 38 | |||
| 39 | Result GetSetupResultValueImpl() override { | ||
| 40 | R_SUCCEED(); | ||
| 41 | } | ||
| 42 | |||
| 43 | private: | ||
| 44 | Core::System& m_system; | ||
| 45 | |||
| 46 | std::mutex m_mutex; | ||
| 47 | s64 m_test_offset{}; | ||
| 48 | s64 m_internal_offset{}; | ||
| 49 | ClockSourceId m_clock_source_id{}; | ||
| 50 | s64 m_rtc_offset{}; | ||
| 51 | s64 m_cached_time_point{}; | ||
| 52 | ContinuousAdjustmentTimePoint m_continuous_adjustment_time_point{}; | ||
| 53 | }; | ||
| 54 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp new file mode 100644 index 000000000..9e9be05d6 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | |||
| 9 | StandardUserSystemClockCore::StandardUserSystemClockCore( | ||
| 10 | Core::System& system, StandardLocalSystemClockCore& local_clock, | ||
| 11 | StandardNetworkSystemClockCore& network_clock) | ||
| 12 | : SystemClockCore{local_clock.GetSteadyClock()}, m_system{system}, | ||
| 13 | m_ctx{m_system, "Psc:StandardUserSystemClockCore"}, m_local_system_clock{local_clock}, | ||
| 14 | m_network_system_clock{network_clock}, m_event{m_ctx.CreateEvent( | ||
| 15 | "Psc:StandardUserSystemClockCore:Event")} {} | ||
| 16 | |||
| 17 | StandardUserSystemClockCore::~StandardUserSystemClockCore() { | ||
| 18 | m_ctx.CloseEvent(m_event); | ||
| 19 | } | ||
| 20 | |||
| 21 | Result StandardUserSystemClockCore::SetAutomaticCorrection(bool automatic_correction) { | ||
| 22 | R_SUCCEED_IF(m_automatic_correction == automatic_correction); | ||
| 23 | R_SUCCEED_IF(!m_network_system_clock.CheckClockSourceMatches()); | ||
| 24 | |||
| 25 | SystemClockContext context{}; | ||
| 26 | R_TRY(m_network_system_clock.GetContext(context)); | ||
| 27 | R_TRY(m_local_system_clock.SetContextAndWrite(context)); | ||
| 28 | |||
| 29 | m_automatic_correction = automatic_correction; | ||
| 30 | R_SUCCEED(); | ||
| 31 | } | ||
| 32 | |||
| 33 | Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context) const { | ||
| 34 | if (!m_automatic_correction) { | ||
| 35 | R_RETURN(m_local_system_clock.GetContext(out_context)); | ||
| 36 | } | ||
| 37 | |||
| 38 | if (!m_network_system_clock.CheckClockSourceMatches()) { | ||
| 39 | R_RETURN(m_local_system_clock.GetContext(out_context)); | ||
| 40 | } | ||
| 41 | |||
| 42 | SystemClockContext context{}; | ||
| 43 | R_TRY(m_network_system_clock.GetContext(context)); | ||
| 44 | R_TRY(m_local_system_clock.SetContextAndWrite(context)); | ||
| 45 | |||
| 46 | R_RETURN(m_local_system_clock.GetContext(out_context)); | ||
| 47 | } | ||
| 48 | |||
| 49 | Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) { | ||
| 50 | R_RETURN(ResultNotImplemented); | ||
| 51 | } | ||
| 52 | |||
| 53 | Result StandardUserSystemClockCore::GetTimePoint(SteadyClockTimePoint& out_time_point) { | ||
| 54 | out_time_point = m_time_point; | ||
| 55 | R_SUCCEED(); | ||
| 56 | } | ||
| 57 | |||
| 58 | void StandardUserSystemClockCore::SetTimePointAndSignal(SteadyClockTimePoint& time_point) { | ||
| 59 | m_time_point = time_point; | ||
| 60 | m_event->Signal(); | ||
| 61 | } | ||
| 62 | |||
| 63 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h new file mode 100644 index 000000000..a7fe7648d --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_event.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "core/hle/service/kernel_helpers.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 10 | #include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" | ||
| 11 | #include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" | ||
| 12 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 13 | #include "core/hle/service/psc/time/clocks/system_clock_core.h" | ||
| 14 | #include "core/hle/service/psc/time/common.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::PSC::Time { | ||
| 21 | |||
| 22 | class StandardUserSystemClockCore : public SystemClockCore { | ||
| 23 | public: | ||
| 24 | explicit StandardUserSystemClockCore(Core::System& system, | ||
| 25 | StandardLocalSystemClockCore& local_clock, | ||
| 26 | StandardNetworkSystemClockCore& network_clock); | ||
| 27 | ~StandardUserSystemClockCore() override; | ||
| 28 | |||
| 29 | Kernel::KEvent& GetEvent() { | ||
| 30 | return *m_event; | ||
| 31 | } | ||
| 32 | |||
| 33 | bool GetAutomaticCorrection() const { | ||
| 34 | return m_automatic_correction; | ||
| 35 | } | ||
| 36 | Result SetAutomaticCorrection(bool automatic_correction); | ||
| 37 | |||
| 38 | Result GetContext(SystemClockContext& out_context) const override; | ||
| 39 | Result SetContext(SystemClockContext& context) override; | ||
| 40 | |||
| 41 | Result GetTimePoint(SteadyClockTimePoint& out_time_point); | ||
| 42 | void SetTimePointAndSignal(SteadyClockTimePoint& time_point); | ||
| 43 | |||
| 44 | private: | ||
| 45 | Core::System& m_system; | ||
| 46 | KernelHelpers::ServiceContext m_ctx; | ||
| 47 | |||
| 48 | bool m_automatic_correction{}; | ||
| 49 | StandardLocalSystemClockCore& m_local_system_clock; | ||
| 50 | StandardNetworkSystemClockCore& m_network_system_clock; | ||
| 51 | SteadyClockTimePoint m_time_point{}; | ||
| 52 | Kernel::KEvent* m_event{}; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/steady_clock_core.h b/src/core/hle/service/psc/time/clocks/steady_clock_core.h new file mode 100644 index 000000000..f933cc15f --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/steady_clock_core.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/psc/time/common.h" | ||
| 10 | |||
| 11 | namespace Service::PSC::Time { | ||
| 12 | |||
| 13 | class SteadyClockCore { | ||
| 14 | public: | ||
| 15 | SteadyClockCore() = default; | ||
| 16 | virtual ~SteadyClockCore() = default; | ||
| 17 | |||
| 18 | void SetInitialized() { | ||
| 19 | m_initialized = true; | ||
| 20 | } | ||
| 21 | |||
| 22 | bool IsInitialized() const { | ||
| 23 | return m_initialized; | ||
| 24 | } | ||
| 25 | |||
| 26 | void SetResetDetected() { | ||
| 27 | m_reset_detected = true; | ||
| 28 | } | ||
| 29 | |||
| 30 | bool IsResetDetected() const { | ||
| 31 | return m_reset_detected; | ||
| 32 | } | ||
| 33 | |||
| 34 | Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) { | ||
| 35 | R_TRY(GetCurrentTimePointImpl(out_time_point)); | ||
| 36 | |||
| 37 | auto one_second_ns{ | ||
| 38 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 39 | out_time_point.time_point += GetTestOffsetImpl() / one_second_ns; | ||
| 40 | out_time_point.time_point += GetInternalOffsetImpl() / one_second_ns; | ||
| 41 | R_SUCCEED(); | ||
| 42 | } | ||
| 43 | |||
| 44 | s64 GetTestOffset() const { | ||
| 45 | return GetTestOffsetImpl(); | ||
| 46 | } | ||
| 47 | |||
| 48 | void SetTestOffset(s64 offset) { | ||
| 49 | SetTestOffsetImpl(offset); | ||
| 50 | } | ||
| 51 | |||
| 52 | s64 GetInternalOffset() const { | ||
| 53 | return GetInternalOffsetImpl(); | ||
| 54 | } | ||
| 55 | |||
| 56 | s64 GetRawTime() { | ||
| 57 | return GetCurrentRawTimePointImpl() + GetTestOffsetImpl() + GetInternalOffsetImpl(); | ||
| 58 | } | ||
| 59 | |||
| 60 | Result GetRtcValue(s64& out_value) { | ||
| 61 | R_RETURN(GetRtcValueImpl(out_value)); | ||
| 62 | } | ||
| 63 | |||
| 64 | Result GetSetupResultValue() { | ||
| 65 | R_RETURN(GetSetupResultValueImpl()); | ||
| 66 | } | ||
| 67 | |||
| 68 | private: | ||
| 69 | virtual Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) = 0; | ||
| 70 | virtual s64 GetCurrentRawTimePointImpl() = 0; | ||
| 71 | virtual s64 GetTestOffsetImpl() const = 0; | ||
| 72 | virtual void SetTestOffsetImpl(s64 offset) = 0; | ||
| 73 | virtual s64 GetInternalOffsetImpl() const = 0; | ||
| 74 | virtual void SetInternalOffsetImpl(s64 offset) = 0; | ||
| 75 | virtual Result GetRtcValueImpl(s64& out_value) = 0; | ||
| 76 | virtual Result GetSetupResultValueImpl() = 0; | ||
| 77 | |||
| 78 | bool m_initialized{}; | ||
| 79 | bool m_reset_detected{}; | ||
| 80 | }; | ||
| 81 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/system_clock_core.cpp new file mode 100644 index 000000000..c507ef517 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/system_clock_core.cpp | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 5 | #include "core/hle/service/psc/time/clocks/system_clock_core.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | |||
| 9 | bool SystemClockCore::CheckClockSourceMatches() { | ||
| 10 | SystemClockContext context{}; | ||
| 11 | if (GetContext(context) != ResultSuccess) { | ||
| 12 | return false; | ||
| 13 | } | ||
| 14 | |||
| 15 | SteadyClockTimePoint time_point{}; | ||
| 16 | if (m_steady_clock.GetCurrentTimePoint(time_point) != ResultSuccess) { | ||
| 17 | return false; | ||
| 18 | } | ||
| 19 | |||
| 20 | return context.steady_time_point.IdMatches(time_point); | ||
| 21 | } | ||
| 22 | |||
| 23 | Result SystemClockCore::GetCurrentTime(s64* out_time) const { | ||
| 24 | R_UNLESS(out_time != nullptr, ResultInvalidArgument); | ||
| 25 | |||
| 26 | SystemClockContext context{}; | ||
| 27 | SteadyClockTimePoint time_point{}; | ||
| 28 | |||
| 29 | R_TRY(m_steady_clock.GetCurrentTimePoint(time_point)); | ||
| 30 | R_TRY(GetContext(context)); | ||
| 31 | |||
| 32 | R_UNLESS(context.steady_time_point.IdMatches(time_point), ResultClockMismatch); | ||
| 33 | |||
| 34 | *out_time = context.offset + time_point.time_point; | ||
| 35 | R_SUCCEED(); | ||
| 36 | } | ||
| 37 | |||
| 38 | Result SystemClockCore::SetCurrentTime(s64 time) { | ||
| 39 | SteadyClockTimePoint time_point{}; | ||
| 40 | R_TRY(m_steady_clock.GetCurrentTimePoint(time_point)); | ||
| 41 | |||
| 42 | SystemClockContext context{ | ||
| 43 | .offset = time - time_point.time_point, | ||
| 44 | .steady_time_point = time_point, | ||
| 45 | }; | ||
| 46 | R_RETURN(SetContextAndWrite(context)); | ||
| 47 | } | ||
| 48 | |||
| 49 | Result SystemClockCore::GetContext(SystemClockContext& out_context) const { | ||
| 50 | out_context = m_context; | ||
| 51 | R_SUCCEED(); | ||
| 52 | } | ||
| 53 | |||
| 54 | Result SystemClockCore::SetContext(SystemClockContext& context) { | ||
| 55 | m_context = context; | ||
| 56 | R_SUCCEED(); | ||
| 57 | } | ||
| 58 | |||
| 59 | Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) { | ||
| 60 | R_TRY(SetContext(context)); | ||
| 61 | |||
| 62 | if (m_context_writer) { | ||
| 63 | R_RETURN(m_context_writer->Write(context)); | ||
| 64 | } | ||
| 65 | |||
| 66 | R_SUCCEED(); | ||
| 67 | } | ||
| 68 | |||
| 69 | void SystemClockCore::LinkOperationEvent(OperationEvent& operation_event) { | ||
| 70 | if (m_context_writer) { | ||
| 71 | m_context_writer->Link(operation_event); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/system_clock_core.h b/src/core/hle/service/psc/time/clocks/system_clock_core.h new file mode 100644 index 000000000..73811712e --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/system_clock_core.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 8 | #include "core/hle/service/psc/time/common.h" | ||
| 9 | |||
| 10 | namespace Service::PSC::Time { | ||
| 11 | class ContextWriter; | ||
| 12 | |||
| 13 | class SystemClockCore { | ||
| 14 | public: | ||
| 15 | explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {} | ||
| 16 | virtual ~SystemClockCore() = default; | ||
| 17 | |||
| 18 | SteadyClockCore& GetSteadyClock() { | ||
| 19 | return m_steady_clock; | ||
| 20 | } | ||
| 21 | |||
| 22 | bool IsInitialized() const { | ||
| 23 | return m_initialized; | ||
| 24 | } | ||
| 25 | |||
| 26 | void SetInitialized() { | ||
| 27 | m_initialized = true; | ||
| 28 | } | ||
| 29 | |||
| 30 | void SetContextWriter(ContextWriter& context_writer) { | ||
| 31 | m_context_writer = &context_writer; | ||
| 32 | } | ||
| 33 | |||
| 34 | bool CheckClockSourceMatches(); | ||
| 35 | |||
| 36 | Result GetCurrentTime(s64* out_time) const; | ||
| 37 | Result SetCurrentTime(s64 time); | ||
| 38 | |||
| 39 | Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) { | ||
| 40 | R_RETURN(m_steady_clock.GetCurrentTimePoint(out_time_point)); | ||
| 41 | } | ||
| 42 | |||
| 43 | virtual Result GetContext(SystemClockContext& out_context) const; | ||
| 44 | virtual Result SetContext(SystemClockContext& context); | ||
| 45 | Result SetContextAndWrite(SystemClockContext& context); | ||
| 46 | |||
| 47 | void LinkOperationEvent(OperationEvent& operation_event); | ||
| 48 | |||
| 49 | private: | ||
| 50 | bool m_initialized{}; | ||
| 51 | ContextWriter* m_context_writer{}; | ||
| 52 | SteadyClockCore& m_steady_clock; | ||
| 53 | SystemClockContext m_context{}; | ||
| 54 | }; | ||
| 55 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp new file mode 100644 index 000000000..22da1fbcc --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | |||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | #include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Service::PSC::Time { | ||
| 11 | |||
| 12 | Result TickBasedSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) { | ||
| 13 | auto ticks{m_system.CoreTiming().GetClockTicks()}; | ||
| 14 | auto current_time_s = | ||
| 15 | std::chrono::duration_cast<std::chrono::seconds>(ConvertToTimeSpan(ticks)).count(); | ||
| 16 | out_time_point.time_point = current_time_s; | ||
| 17 | out_time_point.clock_source_id = m_clock_source_id; | ||
| 18 | R_SUCCEED(); | ||
| 19 | } | ||
| 20 | |||
| 21 | s64 TickBasedSteadyClockCore::GetCurrentRawTimePointImpl() { | ||
| 22 | SteadyClockTimePoint time_point{}; | ||
| 23 | if (GetCurrentTimePointImpl(time_point) != ResultSuccess) { | ||
| 24 | LOG_ERROR(Service_Time, "Failed to GetCurrentTimePoint!"); | ||
| 25 | } | ||
| 26 | return std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
| 27 | std::chrono::seconds(time_point.time_point)) | ||
| 28 | .count(); | ||
| 29 | } | ||
| 30 | |||
| 31 | s64 TickBasedSteadyClockCore::GetTestOffsetImpl() const { | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | void TickBasedSteadyClockCore::SetTestOffsetImpl(s64 offset) {} | ||
| 36 | |||
| 37 | s64 TickBasedSteadyClockCore::GetInternalOffsetImpl() const { | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | void TickBasedSteadyClockCore::SetInternalOffsetImpl(s64 offset) {} | ||
| 42 | |||
| 43 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h new file mode 100644 index 000000000..a7bea86a2 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "common/uuid.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/steady_clock_core.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::PSC::Time { | ||
| 16 | class TickBasedSteadyClockCore : public SteadyClockCore { | ||
| 17 | public: | ||
| 18 | explicit TickBasedSteadyClockCore(Core::System& system) : m_system{system} {} | ||
| 19 | ~TickBasedSteadyClockCore() override = default; | ||
| 20 | |||
| 21 | Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override; | ||
| 22 | s64 GetCurrentRawTimePointImpl() override; | ||
| 23 | s64 GetTestOffsetImpl() const override; | ||
| 24 | void SetTestOffsetImpl(s64 offset) override; | ||
| 25 | s64 GetInternalOffsetImpl() const override; | ||
| 26 | void SetInternalOffsetImpl(s64 offset) override; | ||
| 27 | |||
| 28 | Result GetRtcValueImpl(s64& out_value) override { | ||
| 29 | R_RETURN(ResultNotImplemented); | ||
| 30 | } | ||
| 31 | |||
| 32 | Result GetSetupResultValueImpl() override { | ||
| 33 | R_SUCCEED(); | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | Core::System& m_system; | ||
| 38 | |||
| 39 | ClockSourceId m_clock_source_id{Common::UUID::MakeRandom()}; | ||
| 40 | }; | ||
| 41 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/common.cpp b/src/core/hle/service/psc/time/common.cpp new file mode 100644 index 000000000..a6d9f02ca --- /dev/null +++ b/src/core/hle/service/psc/time/common.cpp | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/common.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | OperationEvent::OperationEvent(Core::System& system) | ||
| 9 | : m_ctx{system, "Time:OperationEvent"}, m_event{ | ||
| 10 | m_ctx.CreateEvent("Time:OperationEvent:Event")} {} | ||
| 11 | |||
| 12 | OperationEvent::~OperationEvent() { | ||
| 13 | m_ctx.CloseEvent(m_event); | ||
| 14 | } | ||
| 15 | |||
| 16 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h new file mode 100644 index 000000000..d17b31143 --- /dev/null +++ b/src/core/hle/service/psc/time/common.h | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <chrono> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/intrusive_list.h" | ||
| 11 | #include "common/uuid.h" | ||
| 12 | #include "common/wall_clock.h" | ||
| 13 | #include "core/hle/kernel/k_event.h" | ||
| 14 | #include "core/hle/service/kernel_helpers.h" | ||
| 15 | #include "core/hle/service/psc/time/errors.h" | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Service::PSC::Time { | ||
| 22 | using ClockSourceId = Common::UUID; | ||
| 23 | |||
| 24 | struct SteadyClockTimePoint { | ||
| 25 | constexpr bool IdMatches(SteadyClockTimePoint& other) { | ||
| 26 | return clock_source_id == other.clock_source_id; | ||
| 27 | } | ||
| 28 | bool operator==(const SteadyClockTimePoint& other) const = default; | ||
| 29 | |||
| 30 | s64 time_point; | ||
| 31 | ClockSourceId clock_source_id; | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint has the wrong size!"); | ||
| 34 | static_assert(std::is_trivial_v<ClockSourceId>); | ||
| 35 | |||
| 36 | struct SystemClockContext { | ||
| 37 | bool operator==(const SystemClockContext& other) const = default; | ||
| 38 | |||
| 39 | s64 offset; | ||
| 40 | SteadyClockTimePoint steady_time_point; | ||
| 41 | }; | ||
| 42 | static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!"); | ||
| 43 | static_assert(std::is_trivial_v<SystemClockContext>); | ||
| 44 | |||
| 45 | enum class TimeType : u8 { | ||
| 46 | UserSystemClock, | ||
| 47 | NetworkSystemClock, | ||
| 48 | LocalSystemClock, | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct CalendarTime { | ||
| 52 | s16 year; | ||
| 53 | s8 month; | ||
| 54 | s8 day; | ||
| 55 | s8 hour; | ||
| 56 | s8 minute; | ||
| 57 | s8 second; | ||
| 58 | }; | ||
| 59 | static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime has the wrong size!"); | ||
| 60 | |||
| 61 | struct CalendarAdditionalInfo { | ||
| 62 | s32 day_of_week; | ||
| 63 | s32 day_of_year; | ||
| 64 | std::array<char, 8> name; | ||
| 65 | s32 is_dst; | ||
| 66 | s32 ut_offset; | ||
| 67 | }; | ||
| 68 | static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!"); | ||
| 69 | |||
| 70 | struct LocationName { | ||
| 71 | std::array<char, 36> name; | ||
| 72 | }; | ||
| 73 | static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!"); | ||
| 74 | |||
| 75 | struct RuleVersion { | ||
| 76 | std::array<char, 16> version; | ||
| 77 | }; | ||
| 78 | static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!"); | ||
| 79 | |||
| 80 | struct ClockSnapshot { | ||
| 81 | SystemClockContext user_context; | ||
| 82 | SystemClockContext network_context; | ||
| 83 | s64 user_time; | ||
| 84 | s64 network_time; | ||
| 85 | CalendarTime user_calendar_time; | ||
| 86 | CalendarTime network_calendar_time; | ||
| 87 | CalendarAdditionalInfo user_calendar_additional_time; | ||
| 88 | CalendarAdditionalInfo network_calendar_additional_time; | ||
| 89 | SteadyClockTimePoint steady_clock_time_point; | ||
| 90 | LocationName location_name; | ||
| 91 | bool is_automatic_correction_enabled; | ||
| 92 | TimeType type; | ||
| 93 | u16 unk_CE; | ||
| 94 | }; | ||
| 95 | static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot has the wrong size!"); | ||
| 96 | static_assert(std::is_trivial_v<ClockSnapshot>); | ||
| 97 | |||
| 98 | struct ContinuousAdjustmentTimePoint { | ||
| 99 | s64 rtc_offset; | ||
| 100 | s64 diff_scale; | ||
| 101 | s64 shift_amount; | ||
| 102 | s64 lower; | ||
| 103 | s64 upper; | ||
| 104 | ClockSourceId clock_source_id; | ||
| 105 | }; | ||
| 106 | static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38, | ||
| 107 | "ContinuousAdjustmentTimePoint has the wrong size!"); | ||
| 108 | static_assert(std::is_trivial_v<ContinuousAdjustmentTimePoint>); | ||
| 109 | |||
| 110 | struct AlarmInfo { | ||
| 111 | s64 alert_time; | ||
| 112 | u32 priority; | ||
| 113 | }; | ||
| 114 | static_assert(sizeof(AlarmInfo) == 0x10, "AlarmInfo has the wrong size!"); | ||
| 115 | |||
| 116 | struct StaticServiceSetupInfo { | ||
| 117 | bool can_write_local_clock; | ||
| 118 | bool can_write_user_clock; | ||
| 119 | bool can_write_network_clock; | ||
| 120 | bool can_write_timezone_device_location; | ||
| 121 | bool can_write_steady_clock; | ||
| 122 | bool can_write_uninitialized_clock; | ||
| 123 | }; | ||
| 124 | static_assert(sizeof(StaticServiceSetupInfo) == 0x6, "StaticServiceSetupInfo has the wrong size!"); | ||
| 125 | |||
| 126 | struct OperationEvent : public Common::IntrusiveListBaseNode<OperationEvent> { | ||
| 127 | using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType; | ||
| 128 | |||
| 129 | OperationEvent(Core::System& system); | ||
| 130 | ~OperationEvent(); | ||
| 131 | |||
| 132 | KernelHelpers::ServiceContext m_ctx; | ||
| 133 | Kernel::KEvent* m_event{}; | ||
| 134 | }; | ||
| 135 | |||
| 136 | constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) { | ||
| 137 | constexpr auto one_second_ns{ | ||
| 138 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 139 | |||
| 140 | constexpr s64 max{Common::WallClock::CNTFRQ * | ||
| 141 | (std::numeric_limits<s64>::max() / one_second_ns)}; | ||
| 142 | |||
| 143 | if (ticks > max) { | ||
| 144 | return std::chrono::nanoseconds(std::numeric_limits<s64>::max()); | ||
| 145 | } else if (ticks < -max) { | ||
| 146 | return std::chrono::nanoseconds(std::numeric_limits<s64>::min()); | ||
| 147 | } | ||
| 148 | |||
| 149 | auto a{ticks / Common::WallClock::CNTFRQ * one_second_ns}; | ||
| 150 | auto b{((ticks % Common::WallClock::CNTFRQ) * one_second_ns) / Common::WallClock::CNTFRQ}; | ||
| 151 | |||
| 152 | return std::chrono::nanoseconds(a + b); | ||
| 153 | } | ||
| 154 | |||
| 155 | constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTimePoint& a, | ||
| 156 | SteadyClockTimePoint& b) { | ||
| 157 | R_UNLESS(out_seconds, ResultInvalidArgument); | ||
| 158 | R_UNLESS(a.IdMatches(b), ResultInvalidArgument); | ||
| 159 | R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(), | ||
| 160 | ResultOverflow); | ||
| 161 | R_UNLESS(a.time_point < 0 || b.time_point >= a.time_point + std::numeric_limits<s64>::min(), | ||
| 162 | ResultOverflow); | ||
| 163 | |||
| 164 | *out_seconds = b.time_point - a.time_point; | ||
| 165 | R_SUCCEED(); | ||
| 166 | } | ||
| 167 | |||
| 168 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/errors.h b/src/core/hle/service/psc/time/errors.h new file mode 100644 index 000000000..6d833a006 --- /dev/null +++ b/src/core/hle/service/psc/time/errors.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | |||
| 8 | namespace Service::PSC::Time { | ||
| 9 | |||
| 10 | constexpr Result ResultPermissionDenied{ErrorModule::Time, 1}; | ||
| 11 | constexpr Result ResultClockMismatch{ErrorModule::Time, 102}; | ||
| 12 | constexpr Result ResultClockUninitialized{ErrorModule::Time, 103}; | ||
| 13 | constexpr Result ResultTimeNotFound{ErrorModule::Time, 200}; | ||
| 14 | constexpr Result ResultOverflow{ErrorModule::Time, 201}; | ||
| 15 | constexpr Result ResultFailed{ErrorModule::Time, 801}; | ||
| 16 | constexpr Result ResultInvalidArgument{ErrorModule::Time, 901}; | ||
| 17 | constexpr Result ResultTimeZoneOutOfRange{ErrorModule::Time, 902}; | ||
| 18 | constexpr Result ResultTimeZoneParseFailed{ErrorModule::Time, 903}; | ||
| 19 | constexpr Result ResultRtcTimeout{ErrorModule::Time, 988}; | ||
| 20 | constexpr Result ResultTimeZoneNotFound{ErrorModule::Time, 989}; | ||
| 21 | constexpr Result ResultNotImplemented{ErrorModule::Time, 990}; | ||
| 22 | constexpr Result ResultAlarmNotRegistered{ErrorModule::Time, 1502}; | ||
| 23 | |||
| 24 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/manager.h b/src/core/hle/service/psc/time/manager.h new file mode 100644 index 000000000..62ded1247 --- /dev/null +++ b/src/core/hle/service/psc/time/manager.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/psc/time/alarms.h" | ||
| 7 | #include "core/hle/service/psc/time/clocks/context_writers.h" | ||
| 8 | #include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" | ||
| 10 | #include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" | ||
| 11 | #include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h" | ||
| 12 | #include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h" | ||
| 13 | #include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h" | ||
| 14 | #include "core/hle/service/psc/time/power_state_request_manager.h" | ||
| 15 | #include "core/hle/service/psc/time/shared_memory.h" | ||
| 16 | #include "core/hle/service/psc/time/time_zone.h" | ||
| 17 | |||
| 18 | namespace Core { | ||
| 19 | class System; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Service::PSC::Time { | ||
| 23 | class TimeManager { | ||
| 24 | public: | ||
| 25 | explicit TimeManager(Core::System& system) | ||
| 26 | : m_system{system}, m_standard_steady_clock{system}, m_tick_based_steady_clock{m_system}, | ||
| 27 | m_standard_local_system_clock{m_standard_steady_clock}, | ||
| 28 | m_standard_network_system_clock{m_standard_steady_clock}, | ||
| 29 | m_standard_user_system_clock{m_system, m_standard_local_system_clock, | ||
| 30 | m_standard_network_system_clock}, | ||
| 31 | m_ephemeral_network_clock{m_tick_based_steady_clock}, m_shared_memory{m_system}, | ||
| 32 | m_power_state_request_manager{m_system}, m_alarms{m_system, m_standard_steady_clock, | ||
| 33 | m_power_state_request_manager}, | ||
| 34 | m_local_system_clock_context_writer{m_system, m_shared_memory}, | ||
| 35 | m_network_system_clock_context_writer{m_system, m_shared_memory, | ||
| 36 | m_standard_user_system_clock}, | ||
| 37 | m_ephemeral_network_clock_context_writer{m_system} {} | ||
| 38 | |||
| 39 | Core::System& m_system; | ||
| 40 | |||
| 41 | StandardSteadyClockCore m_standard_steady_clock; | ||
| 42 | TickBasedSteadyClockCore m_tick_based_steady_clock; | ||
| 43 | StandardLocalSystemClockCore m_standard_local_system_clock; | ||
| 44 | StandardNetworkSystemClockCore m_standard_network_system_clock; | ||
| 45 | StandardUserSystemClockCore m_standard_user_system_clock; | ||
| 46 | EphemeralNetworkSystemClockCore m_ephemeral_network_clock; | ||
| 47 | TimeZone m_time_zone; | ||
| 48 | SharedMemory m_shared_memory; | ||
| 49 | PowerStateRequestManager m_power_state_request_manager; | ||
| 50 | Alarms m_alarms; | ||
| 51 | LocalSystemClockContextWriter m_local_system_clock_context_writer; | ||
| 52 | NetworkSystemClockContextWriter m_network_system_clock_context_writer; | ||
| 53 | EphemeralNetworkSystemClockContextWriter m_ephemeral_network_clock_context_writer; | ||
| 54 | }; | ||
| 55 | |||
| 56 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/power_state_request_manager.cpp b/src/core/hle/service/psc/time/power_state_request_manager.cpp new file mode 100644 index 000000000..17de0bf4d --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_request_manager.cpp | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/power_state_request_manager.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | |||
| 9 | PowerStateRequestManager::PowerStateRequestManager(Core::System& system) | ||
| 10 | : m_system{system}, m_ctx{system, "Psc:PowerStateRequestManager"}, | ||
| 11 | m_event{m_ctx.CreateEvent("Psc:PowerStateRequestManager:Event")} {} | ||
| 12 | |||
| 13 | PowerStateRequestManager::~PowerStateRequestManager() { | ||
| 14 | m_ctx.CloseEvent(m_event); | ||
| 15 | } | ||
| 16 | |||
| 17 | void PowerStateRequestManager::UpdatePendingPowerStateRequestPriority(u32 priority) { | ||
| 18 | std::scoped_lock l{m_mutex}; | ||
| 19 | if (m_has_pending_request) { | ||
| 20 | m_pending_request_priority = std::max(m_pending_request_priority, priority); | ||
| 21 | } else { | ||
| 22 | m_pending_request_priority = priority; | ||
| 23 | m_has_pending_request = true; | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | void PowerStateRequestManager::SignalPowerStateRequestAvailability() { | ||
| 28 | std::scoped_lock l{m_mutex}; | ||
| 29 | if (m_has_pending_request) { | ||
| 30 | if (!m_has_available_request) { | ||
| 31 | m_has_available_request = true; | ||
| 32 | } | ||
| 33 | m_has_pending_request = false; | ||
| 34 | m_available_request_priority = m_pending_request_priority; | ||
| 35 | m_event->Signal(); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | bool PowerStateRequestManager::GetAndClearPowerStateRequest(u32& out_priority) { | ||
| 40 | std::scoped_lock l{m_mutex}; | ||
| 41 | auto had_request{m_has_available_request}; | ||
| 42 | if (m_has_available_request) { | ||
| 43 | out_priority = m_available_request_priority; | ||
| 44 | m_has_available_request = false; | ||
| 45 | m_event->Clear(); | ||
| 46 | } | ||
| 47 | return had_request; | ||
| 48 | } | ||
| 49 | |||
| 50 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/power_state_request_manager.h b/src/core/hle/service/psc/time/power_state_request_manager.h new file mode 100644 index 000000000..30a0c947d --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_request_manager.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "core/hle/kernel/k_event.h" | ||
| 9 | #include "core/hle/service/kernel_helpers.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::PSC::Time { | ||
| 16 | |||
| 17 | class PowerStateRequestManager { | ||
| 18 | public: | ||
| 19 | explicit PowerStateRequestManager(Core::System& system); | ||
| 20 | ~PowerStateRequestManager(); | ||
| 21 | |||
| 22 | Kernel::KReadableEvent& GetReadableEvent() { | ||
| 23 | return m_event->GetReadableEvent(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void UpdatePendingPowerStateRequestPriority(u32 priority); | ||
| 27 | void SignalPowerStateRequestAvailability(); | ||
| 28 | bool GetAndClearPowerStateRequest(u32& out_priority); | ||
| 29 | |||
| 30 | private: | ||
| 31 | Core::System& m_system; | ||
| 32 | KernelHelpers::ServiceContext m_ctx; | ||
| 33 | |||
| 34 | Kernel::KEvent* m_event{}; | ||
| 35 | bool m_has_pending_request{}; | ||
| 36 | u32 m_pending_request_priority{}; | ||
| 37 | bool m_has_available_request{}; | ||
| 38 | u32 m_available_request_priority{}; | ||
| 39 | std::mutex m_mutex; | ||
| 40 | }; | ||
| 41 | |||
| 42 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/power_state_service.cpp b/src/core/hle/service/psc/time/power_state_service.cpp new file mode 100644 index 000000000..b0ae71bf9 --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_service.cpp | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/psc/time/power_state_service.h" | ||
| 5 | |||
| 6 | namespace Service::PSC::Time { | ||
| 7 | |||
| 8 | IPowerStateRequestHandler::IPowerStateRequestHandler( | ||
| 9 | Core::System& system_, PowerStateRequestManager& power_state_request_manager) | ||
| 10 | : ServiceFramework{system_, "time:p"}, m_system{system}, m_power_state_request_manager{ | ||
| 11 | power_state_request_manager} { | ||
| 12 | // clang-format off | ||
| 13 | static const FunctionInfo functions[] = { | ||
| 14 | {0, &IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle, "GetPowerStateRequestEventReadableHandle"}, | ||
| 15 | {1, &IPowerStateRequestHandler::GetAndClearPowerStateRequest, "GetAndClearPowerStateRequest"}, | ||
| 16 | }; | ||
| 17 | // clang-format on | ||
| 18 | |||
| 19 | RegisterHandlers(functions); | ||
| 20 | } | ||
| 21 | |||
| 22 | void IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx) { | ||
| 23 | LOG_DEBUG(Service_Time, "called."); | ||
| 24 | |||
| 25 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 26 | rb.Push(ResultSuccess); | ||
| 27 | rb.PushCopyObjects(m_power_state_request_manager.GetReadableEvent()); | ||
| 28 | } | ||
| 29 | |||
| 30 | void IPowerStateRequestHandler::GetAndClearPowerStateRequest(HLERequestContext& ctx) { | ||
| 31 | LOG_DEBUG(Service_Time, "called."); | ||
| 32 | |||
| 33 | u32 priority{}; | ||
| 34 | auto cleared = m_power_state_request_manager.GetAndClearPowerStateRequest(priority); | ||
| 35 | |||
| 36 | if (cleared) { | ||
| 37 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 38 | rb.Push(ResultSuccess); | ||
| 39 | rb.Push(priority); | ||
| 40 | rb.Push(cleared); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | |||
| 44 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 45 | rb.Push(ResultSuccess); | ||
| 46 | rb.Push(cleared); | ||
| 47 | } | ||
| 48 | |||
| 49 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/power_state_service.h b/src/core/hle/service/psc/time/power_state_service.h new file mode 100644 index 000000000..3ebfddb79 --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_service.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/psc/time/power_state_request_manager.h" | ||
| 8 | #include "core/hle/service/server_manager.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::PSC::Time { | ||
| 16 | |||
| 17 | class IPowerStateRequestHandler final : public ServiceFramework<IPowerStateRequestHandler> { | ||
| 18 | public: | ||
| 19 | explicit IPowerStateRequestHandler(Core::System& system, | ||
| 20 | PowerStateRequestManager& power_state_request_manager); | ||
| 21 | |||
| 22 | ~IPowerStateRequestHandler() override = default; | ||
| 23 | |||
| 24 | private: | ||
| 25 | void GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx); | ||
| 26 | void GetAndClearPowerStateRequest(HLERequestContext& ctx); | ||
| 27 | |||
| 28 | Core::System& m_system; | ||
| 29 | PowerStateRequestManager& m_power_state_request_manager; | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/service_manager.cpp b/src/core/hle/service/psc/time/service_manager.cpp new file mode 100644 index 000000000..60820aa9b --- /dev/null +++ b/src/core/hle/service/psc/time/service_manager.cpp | |||
| @@ -0,0 +1,494 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hle/service/psc/time/power_state_service.h" | ||
| 7 | #include "core/hle/service/psc/time/service_manager.h" | ||
| 8 | #include "core/hle/service/psc/time/static.h" | ||
| 9 | |||
| 10 | namespace Service::PSC::Time { | ||
| 11 | |||
| 12 | ServiceManager::ServiceManager(Core::System& system_, std::shared_ptr<TimeManager> time, | ||
| 13 | ServerManager* server_manager) | ||
| 14 | : ServiceFramework{system_, "time:m"}, m_system{system}, m_time{std::move(time)}, | ||
| 15 | m_server_manager{*server_manager}, | ||
| 16 | m_local_system_clock{m_time->m_standard_local_system_clock}, | ||
| 17 | m_user_system_clock{m_time->m_standard_user_system_clock}, | ||
| 18 | m_network_system_clock{m_time->m_standard_network_system_clock}, | ||
| 19 | m_steady_clock{m_time->m_standard_steady_clock}, m_time_zone{m_time->m_time_zone}, | ||
| 20 | m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, | ||
| 21 | m_shared_memory{m_time->m_shared_memory}, m_alarms{m_time->m_alarms}, | ||
| 22 | m_local_system_context_writer{m_time->m_local_system_clock_context_writer}, | ||
| 23 | m_network_system_context_writer{m_time->m_network_system_clock_context_writer}, | ||
| 24 | m_ephemeral_system_context_writer{m_time->m_ephemeral_network_clock_context_writer}, | ||
| 25 | m_local_operation{m_system}, m_network_operation{m_system}, m_ephemeral_operation{m_system} { | ||
| 26 | // clang-format off | ||
| 27 | static const FunctionInfo functions[] = { | ||
| 28 | {0, &ServiceManager::Handle_GetStaticServiceAsUser, "GetStaticServiceAsUser"}, | ||
| 29 | {5, &ServiceManager::Handle_GetStaticServiceAsAdmin, "GetStaticServiceAsAdmin"}, | ||
| 30 | {6, &ServiceManager::Handle_GetStaticServiceAsRepair, "GetStaticServiceAsRepair"}, | ||
| 31 | {9, &ServiceManager::Handle_GetStaticServiceAsServiceManager, "GetStaticServiceAsServiceManager"}, | ||
| 32 | {10, &ServiceManager::Handle_SetupStandardSteadyClockCore, "SetupStandardSteadyClockCore"}, | ||
| 33 | {11, &ServiceManager::Handle_SetupStandardLocalSystemClockCore, "SetupStandardLocalSystemClockCore"}, | ||
| 34 | {12, &ServiceManager::Handle_SetupStandardNetworkSystemClockCore, "SetupStandardNetworkSystemClockCore"}, | ||
| 35 | {13, &ServiceManager::Handle_SetupStandardUserSystemClockCore, "SetupStandardUserSystemClockCore"}, | ||
| 36 | {14, &ServiceManager::Handle_SetupTimeZoneServiceCore, "SetupTimeZoneServiceCore"}, | ||
| 37 | {15, &ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore, "SetupEphemeralNetworkSystemClockCore"}, | ||
| 38 | {50, &ServiceManager::Handle_GetStandardLocalClockOperationEvent, "GetStandardLocalClockOperationEvent"}, | ||
| 39 | {51, &ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager, "GetStandardNetworkClockOperationEventForServiceManager"}, | ||
| 40 | {52, &ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager, "GetEphemeralNetworkClockOperationEventForServiceManager"}, | ||
| 41 | {60, &ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent, "GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent"}, | ||
| 42 | {100, &ServiceManager::Handle_SetStandardSteadyClockBaseTime, "SetStandardSteadyClockBaseTime"}, | ||
| 43 | {200, &ServiceManager::Handle_GetClosestAlarmUpdatedEvent, "GetClosestAlarmUpdatedEvent"}, | ||
| 44 | {201, &ServiceManager::Handle_CheckAndSignalAlarms, "CheckAndSignalAlarms"}, | ||
| 45 | {202, &ServiceManager::Handle_GetClosestAlarmInfo, "GetClosestAlarmInfo "}, | ||
| 46 | }; | ||
| 47 | // clang-format on | ||
| 48 | RegisterHandlers(functions); | ||
| 49 | |||
| 50 | m_local_system_context_writer.Link(m_local_operation); | ||
| 51 | m_network_system_context_writer.Link(m_network_operation); | ||
| 52 | m_ephemeral_system_context_writer.Link(m_ephemeral_operation); | ||
| 53 | } | ||
| 54 | |||
| 55 | void ServiceManager::SetupSAndP() { | ||
| 56 | if (!m_is_s_and_p_setup) { | ||
| 57 | m_is_s_and_p_setup = true; | ||
| 58 | m_server_manager.RegisterNamedService( | ||
| 59 | "time:s", std::make_shared<StaticService>( | ||
| 60 | m_system, StaticServiceSetupInfo{0, 0, 1, 0, 0, 0}, m_time, "time:s")); | ||
| 61 | m_server_manager.RegisterNamedService("time:p", | ||
| 62 | std::make_shared<IPowerStateRequestHandler>( | ||
| 63 | m_system, m_time->m_power_state_request_manager)); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | void ServiceManager::CheckAndSetupServicesSAndP() { | ||
| 68 | if (m_local_system_clock.IsInitialized() && m_user_system_clock.IsInitialized() && | ||
| 69 | m_network_system_clock.IsInitialized() && m_steady_clock.IsInitialized() && | ||
| 70 | m_time_zone.IsInitialized() && m_ephemeral_network_clock.IsInitialized()) { | ||
| 71 | SetupSAndP(); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | void ServiceManager::Handle_GetStaticServiceAsUser(HLERequestContext& ctx) { | ||
| 76 | LOG_DEBUG(Service_Time, "called."); | ||
| 77 | |||
| 78 | std::shared_ptr<StaticService> service{}; | ||
| 79 | auto res = GetStaticServiceAsUser(service); | ||
| 80 | |||
| 81 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 82 | rb.Push(res); | ||
| 83 | rb.PushIpcInterface<StaticService>(std::move(service)); | ||
| 84 | } | ||
| 85 | |||
| 86 | void ServiceManager::Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx) { | ||
| 87 | LOG_DEBUG(Service_Time, "called."); | ||
| 88 | |||
| 89 | std::shared_ptr<StaticService> service{}; | ||
| 90 | auto res = GetStaticServiceAsAdmin(service); | ||
| 91 | |||
| 92 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 93 | rb.Push(res); | ||
| 94 | rb.PushIpcInterface<StaticService>(std::move(service)); | ||
| 95 | } | ||
| 96 | |||
| 97 | void ServiceManager::Handle_GetStaticServiceAsRepair(HLERequestContext& ctx) { | ||
| 98 | LOG_DEBUG(Service_Time, "called."); | ||
| 99 | |||
| 100 | std::shared_ptr<StaticService> service{}; | ||
| 101 | auto res = GetStaticServiceAsRepair(service); | ||
| 102 | |||
| 103 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 104 | rb.Push(res); | ||
| 105 | rb.PushIpcInterface<StaticService>(std::move(service)); | ||
| 106 | } | ||
| 107 | |||
| 108 | void ServiceManager::Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx) { | ||
| 109 | LOG_DEBUG(Service_Time, "called."); | ||
| 110 | |||
| 111 | std::shared_ptr<StaticService> service{}; | ||
| 112 | auto res = GetStaticServiceAsServiceManager(service); | ||
| 113 | |||
| 114 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 115 | rb.Push(res); | ||
| 116 | rb.PushIpcInterface<StaticService>(std::move(service)); | ||
| 117 | } | ||
| 118 | |||
| 119 | void ServiceManager::Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx) { | ||
| 120 | LOG_DEBUG(Service_Time, "called."); | ||
| 121 | |||
| 122 | struct Parameters { | ||
| 123 | bool reset_detected; | ||
| 124 | Common::UUID clock_source_id; | ||
| 125 | s64 rtc_offset; | ||
| 126 | s64 internal_offset; | ||
| 127 | s64 test_offset; | ||
| 128 | }; | ||
| 129 | static_assert(sizeof(Parameters) == 0x30); | ||
| 130 | |||
| 131 | IPC::RequestParser rp{ctx}; | ||
| 132 | auto params{rp.PopRaw<Parameters>()}; | ||
| 133 | |||
| 134 | auto res = SetupStandardSteadyClockCore(params.clock_source_id, params.rtc_offset, | ||
| 135 | params.internal_offset, params.test_offset, | ||
| 136 | params.reset_detected); | ||
| 137 | |||
| 138 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 139 | rb.Push(res); | ||
| 140 | } | ||
| 141 | |||
| 142 | void ServiceManager::Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx) { | ||
| 143 | LOG_DEBUG(Service_Time, "called."); | ||
| 144 | |||
| 145 | IPC::RequestParser rp{ctx}; | ||
| 146 | auto context{rp.PopRaw<SystemClockContext>()}; | ||
| 147 | auto time{rp.Pop<s64>()}; | ||
| 148 | |||
| 149 | auto res = SetupStandardLocalSystemClockCore(context, time); | ||
| 150 | |||
| 151 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 152 | rb.Push(res); | ||
| 153 | } | ||
| 154 | |||
| 155 | void ServiceManager::Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx) { | ||
| 156 | LOG_DEBUG(Service_Time, "called."); | ||
| 157 | |||
| 158 | IPC::RequestParser rp{ctx}; | ||
| 159 | auto context{rp.PopRaw<SystemClockContext>()}; | ||
| 160 | auto accuracy{rp.Pop<s64>()}; | ||
| 161 | |||
| 162 | auto res = SetupStandardNetworkSystemClockCore(context, accuracy); | ||
| 163 | |||
| 164 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 165 | rb.Push(res); | ||
| 166 | } | ||
| 167 | |||
| 168 | void ServiceManager::Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx) { | ||
| 169 | LOG_DEBUG(Service_Time, "called."); | ||
| 170 | |||
| 171 | struct Parameters { | ||
| 172 | bool automatic_correction; | ||
| 173 | SteadyClockTimePoint time_point; | ||
| 174 | }; | ||
| 175 | static_assert(sizeof(Parameters) == 0x20); | ||
| 176 | |||
| 177 | IPC::RequestParser rp{ctx}; | ||
| 178 | auto params{rp.PopRaw<Parameters>()}; | ||
| 179 | |||
| 180 | auto res = SetupStandardUserSystemClockCore(params.time_point, params.automatic_correction); | ||
| 181 | |||
| 182 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 183 | rb.Push(res); | ||
| 184 | } | ||
| 185 | |||
| 186 | void ServiceManager::Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx) { | ||
| 187 | LOG_DEBUG(Service_Time, "called."); | ||
| 188 | |||
| 189 | struct Parameters { | ||
| 190 | u32 location_count; | ||
| 191 | LocationName name; | ||
| 192 | SteadyClockTimePoint time_point; | ||
| 193 | RuleVersion rule_version; | ||
| 194 | }; | ||
| 195 | static_assert(sizeof(Parameters) == 0x50); | ||
| 196 | |||
| 197 | IPC::RequestParser rp{ctx}; | ||
| 198 | auto params{rp.PopRaw<Parameters>()}; | ||
| 199 | |||
| 200 | auto rule_buffer{ctx.ReadBuffer()}; | ||
| 201 | |||
| 202 | auto res = SetupTimeZoneServiceCore(params.name, params.time_point, params.rule_version, | ||
| 203 | params.location_count, rule_buffer); | ||
| 204 | |||
| 205 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 206 | rb.Push(res); | ||
| 207 | } | ||
| 208 | |||
| 209 | void ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx) { | ||
| 210 | LOG_DEBUG(Service_Time, "called."); | ||
| 211 | |||
| 212 | auto res = SetupEphemeralNetworkSystemClockCore(); | ||
| 213 | |||
| 214 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 215 | rb.Push(res); | ||
| 216 | } | ||
| 217 | |||
| 218 | void ServiceManager::Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx) { | ||
| 219 | LOG_DEBUG(Service_Time, "called."); | ||
| 220 | |||
| 221 | Kernel::KEvent* event{}; | ||
| 222 | auto res = GetStandardLocalClockOperationEvent(&event); | ||
| 223 | |||
| 224 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 225 | rb.Push(res); | ||
| 226 | rb.PushCopyObjects(event->GetReadableEvent()); | ||
| 227 | } | ||
| 228 | |||
| 229 | void ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager( | ||
| 230 | HLERequestContext& ctx) { | ||
| 231 | LOG_DEBUG(Service_Time, "called."); | ||
| 232 | |||
| 233 | Kernel::KEvent* event{}; | ||
| 234 | auto res = GetStandardNetworkClockOperationEventForServiceManager(&event); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 237 | rb.Push(res); | ||
| 238 | rb.PushCopyObjects(event); | ||
| 239 | } | ||
| 240 | |||
| 241 | void ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager( | ||
| 242 | HLERequestContext& ctx) { | ||
| 243 | LOG_DEBUG(Service_Time, "called."); | ||
| 244 | |||
| 245 | Kernel::KEvent* event{}; | ||
| 246 | auto res = GetEphemeralNetworkClockOperationEventForServiceManager(&event); | ||
| 247 | |||
| 248 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 249 | rb.Push(res); | ||
| 250 | rb.PushCopyObjects(event); | ||
| 251 | } | ||
| 252 | |||
| 253 | void ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( | ||
| 254 | HLERequestContext& ctx) { | ||
| 255 | LOG_DEBUG(Service_Time, "called."); | ||
| 256 | |||
| 257 | Kernel::KEvent* event{}; | ||
| 258 | auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(&event); | ||
| 259 | |||
| 260 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 261 | rb.Push(res); | ||
| 262 | rb.PushCopyObjects(event); | ||
| 263 | } | ||
| 264 | |||
| 265 | void ServiceManager::Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx) { | ||
| 266 | LOG_DEBUG(Service_Time, "called."); | ||
| 267 | |||
| 268 | IPC::RequestParser rp{ctx}; | ||
| 269 | auto base_time{rp.Pop<s64>()}; | ||
| 270 | |||
| 271 | auto res = SetStandardSteadyClockBaseTime(base_time); | ||
| 272 | |||
| 273 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 274 | rb.Push(res); | ||
| 275 | } | ||
| 276 | |||
| 277 | void ServiceManager::Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx) { | ||
| 278 | LOG_DEBUG(Service_Time, "called."); | ||
| 279 | |||
| 280 | Kernel::KEvent* event{}; | ||
| 281 | auto res = GetClosestAlarmUpdatedEvent(&event); | ||
| 282 | |||
| 283 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 284 | rb.Push(res); | ||
| 285 | rb.PushCopyObjects(event->GetReadableEvent()); | ||
| 286 | } | ||
| 287 | |||
| 288 | void ServiceManager::Handle_CheckAndSignalAlarms(HLERequestContext& ctx) { | ||
| 289 | LOG_DEBUG(Service_Time, "called."); | ||
| 290 | |||
| 291 | auto res = CheckAndSignalAlarms(); | ||
| 292 | |||
| 293 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 294 | rb.Push(res); | ||
| 295 | } | ||
| 296 | |||
| 297 | void ServiceManager::Handle_GetClosestAlarmInfo(HLERequestContext& ctx) { | ||
| 298 | LOG_DEBUG(Service_Time, "called."); | ||
| 299 | |||
| 300 | AlarmInfo alarm_info{}; | ||
| 301 | bool is_valid{}; | ||
| 302 | s64 time{}; | ||
| 303 | auto res = GetClosestAlarmInfo(is_valid, alarm_info, time); | ||
| 304 | |||
| 305 | struct OutParameters { | ||
| 306 | bool is_valid; | ||
| 307 | AlarmInfo alarm_info; | ||
| 308 | s64 time; | ||
| 309 | }; | ||
| 310 | static_assert(sizeof(OutParameters) == 0x20); | ||
| 311 | |||
| 312 | OutParameters out_params{ | ||
| 313 | .is_valid = is_valid, | ||
| 314 | .alarm_info = alarm_info, | ||
| 315 | .time = time, | ||
| 316 | }; | ||
| 317 | |||
| 318 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(OutParameters) / sizeof(u32)}; | ||
| 319 | rb.Push(res); | ||
| 320 | rb.PushRaw<OutParameters>(out_params); | ||
| 321 | } | ||
| 322 | |||
| 323 | // =============================== Implementations =========================== | ||
| 324 | |||
| 325 | Result ServiceManager::GetStaticService(std::shared_ptr<StaticService>& out_service, | ||
| 326 | StaticServiceSetupInfo setup_info, const char* name) { | ||
| 327 | out_service = std::make_shared<StaticService>(m_system, setup_info, m_time, name); | ||
| 328 | R_SUCCEED(); | ||
| 329 | } | ||
| 330 | |||
| 331 | Result ServiceManager::GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service) { | ||
| 332 | R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, "time:u")); | ||
| 333 | } | ||
| 334 | |||
| 335 | Result ServiceManager::GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service) { | ||
| 336 | R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, "time:a")); | ||
| 337 | } | ||
| 338 | |||
| 339 | Result ServiceManager::GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service) { | ||
| 340 | R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, "time:r")); | ||
| 341 | } | ||
| 342 | |||
| 343 | Result ServiceManager::GetStaticServiceAsServiceManager( | ||
| 344 | std::shared_ptr<StaticService>& out_service) { | ||
| 345 | R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 1, 1, 1, 0}, "time:sm")); | ||
| 346 | } | ||
| 347 | |||
| 348 | Result ServiceManager::SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset, | ||
| 349 | s64 internal_offset, s64 test_offset, | ||
| 350 | bool is_rtc_reset_detected) { | ||
| 351 | m_steady_clock.Initialize(clock_source_id, rtc_offset, internal_offset, test_offset, | ||
| 352 | is_rtc_reset_detected); | ||
| 353 | auto time = m_steady_clock.GetRawTime(); | ||
| 354 | auto ticks = m_system.CoreTiming().GetClockTicks(); | ||
| 355 | auto boot_time = time - ConvertToTimeSpan(ticks).count(); | ||
| 356 | m_shared_memory.SetSteadyClockTimePoint(clock_source_id, boot_time); | ||
| 357 | m_steady_clock.SetContinuousAdjustment(clock_source_id, boot_time); | ||
| 358 | |||
| 359 | ContinuousAdjustmentTimePoint time_point{}; | ||
| 360 | m_steady_clock.GetContinuousAdjustment(time_point); | ||
| 361 | m_shared_memory.SetContinuousAdjustment(time_point); | ||
| 362 | |||
| 363 | CheckAndSetupServicesSAndP(); | ||
| 364 | R_SUCCEED(); | ||
| 365 | } | ||
| 366 | |||
| 367 | Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) { | ||
| 368 | m_local_system_clock.SetContextWriter(m_local_system_context_writer); | ||
| 369 | m_local_system_clock.Initialize(context, time); | ||
| 370 | |||
| 371 | CheckAndSetupServicesSAndP(); | ||
| 372 | R_SUCCEED(); | ||
| 373 | } | ||
| 374 | |||
| 375 | Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context, | ||
| 376 | s64 accuracy) { | ||
| 377 | // TODO this is a hack! The network clock should be updated independently, from the ntc service | ||
| 378 | // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot | ||
| 379 | // to avoid it being stuck at 0. | ||
| 380 | if (context == Service::PSC::Time::SystemClockContext{}) { | ||
| 381 | m_local_system_clock.GetContext(context); | ||
| 382 | } | ||
| 383 | |||
| 384 | m_network_system_clock.SetContextWriter(m_network_system_context_writer); | ||
| 385 | m_network_system_clock.Initialize(context, accuracy); | ||
| 386 | |||
| 387 | CheckAndSetupServicesSAndP(); | ||
| 388 | R_SUCCEED(); | ||
| 389 | } | ||
| 390 | |||
| 391 | Result ServiceManager::SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point, | ||
| 392 | bool automatic_correction) { | ||
| 393 | // TODO this is a hack! The user clock should be updated independently, from the ntc service | ||
| 394 | // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot | ||
| 395 | // to avoid it being stuck at 0. | ||
| 396 | if (time_point == Service::PSC::Time::SteadyClockTimePoint{}) { | ||
| 397 | m_local_system_clock.GetCurrentTimePoint(time_point); | ||
| 398 | } | ||
| 399 | |||
| 400 | m_user_system_clock.SetAutomaticCorrection(automatic_correction); | ||
| 401 | m_user_system_clock.SetTimePointAndSignal(time_point); | ||
| 402 | m_user_system_clock.SetInitialized(); | ||
| 403 | m_shared_memory.SetAutomaticCorrection(automatic_correction); | ||
| 404 | |||
| 405 | CheckAndSetupServicesSAndP(); | ||
| 406 | R_SUCCEED(); | ||
| 407 | } | ||
| 408 | |||
| 409 | Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name, | ||
| 410 | SteadyClockTimePoint& time_point, | ||
| 411 | RuleVersion& rule_version, u32 location_count, | ||
| 412 | std::span<const u8> rule_buffer) { | ||
| 413 | if (m_time_zone.ParseBinary(name, rule_buffer) != ResultSuccess) { | ||
| 414 | LOG_ERROR(Service_Time, "Failed to parse time zone binary!"); | ||
| 415 | } | ||
| 416 | |||
| 417 | m_time_zone.SetTimePoint(time_point); | ||
| 418 | m_time_zone.SetTotalLocationNameCount(location_count); | ||
| 419 | m_time_zone.SetRuleVersion(rule_version); | ||
| 420 | m_time_zone.SetInitialized(); | ||
| 421 | |||
| 422 | CheckAndSetupServicesSAndP(); | ||
| 423 | R_SUCCEED(); | ||
| 424 | } | ||
| 425 | |||
| 426 | Result ServiceManager::SetupEphemeralNetworkSystemClockCore() { | ||
| 427 | m_ephemeral_network_clock.SetContextWriter(m_ephemeral_system_context_writer); | ||
| 428 | m_ephemeral_network_clock.SetInitialized(); | ||
| 429 | |||
| 430 | CheckAndSetupServicesSAndP(); | ||
| 431 | R_SUCCEED(); | ||
| 432 | } | ||
| 433 | |||
| 434 | Result ServiceManager::GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event) { | ||
| 435 | *out_event = m_local_operation.m_event; | ||
| 436 | R_SUCCEED(); | ||
| 437 | } | ||
| 438 | |||
| 439 | Result ServiceManager::GetStandardNetworkClockOperationEventForServiceManager( | ||
| 440 | Kernel::KEvent** out_event) { | ||
| 441 | *out_event = m_network_operation.m_event; | ||
| 442 | R_SUCCEED(); | ||
| 443 | } | ||
| 444 | |||
| 445 | Result ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager( | ||
| 446 | Kernel::KEvent** out_event) { | ||
| 447 | *out_event = m_ephemeral_operation.m_event; | ||
| 448 | R_SUCCEED(); | ||
| 449 | } | ||
| 450 | |||
| 451 | Result ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( | ||
| 452 | Kernel::KEvent** out_event) { | ||
| 453 | *out_event = &m_user_system_clock.GetEvent(); | ||
| 454 | R_SUCCEED(); | ||
| 455 | } | ||
| 456 | |||
| 457 | Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) { | ||
| 458 | m_steady_clock.SetRtcOffset(base_time); | ||
| 459 | auto time = m_steady_clock.GetRawTime(); | ||
| 460 | auto ticks = m_system.CoreTiming().GetClockTicks(); | ||
| 461 | auto diff = time - ConvertToTimeSpan(ticks).count(); | ||
| 462 | m_shared_memory.UpdateBaseTime(diff); | ||
| 463 | m_steady_clock.UpdateContinuousAdjustmentTime(diff); | ||
| 464 | |||
| 465 | ContinuousAdjustmentTimePoint time_point{}; | ||
| 466 | m_steady_clock.GetContinuousAdjustment(time_point); | ||
| 467 | m_shared_memory.SetContinuousAdjustment(time_point); | ||
| 468 | R_SUCCEED(); | ||
| 469 | } | ||
| 470 | |||
| 471 | Result ServiceManager::GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event) { | ||
| 472 | *out_event = &m_alarms.GetEvent(); | ||
| 473 | R_SUCCEED(); | ||
| 474 | } | ||
| 475 | |||
| 476 | Result ServiceManager::CheckAndSignalAlarms() { | ||
| 477 | m_alarms.CheckAndSignal(); | ||
| 478 | R_SUCCEED(); | ||
| 479 | } | ||
| 480 | |||
| 481 | Result ServiceManager::GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time) { | ||
| 482 | Alarm* alarm{nullptr}; | ||
| 483 | out_is_valid = m_alarms.GetClosestAlarm(&alarm); | ||
| 484 | if (out_is_valid) { | ||
| 485 | out_info = { | ||
| 486 | .alert_time = alarm->GetAlertTime(), | ||
| 487 | .priority = alarm->GetPriority(), | ||
| 488 | }; | ||
| 489 | out_time = m_alarms.GetRawTime(); | ||
| 490 | } | ||
| 491 | R_SUCCEED(); | ||
| 492 | } | ||
| 493 | |||
| 494 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/service_manager.h b/src/core/hle/service/psc/time/service_manager.h new file mode 100644 index 000000000..1d9952317 --- /dev/null +++ b/src/core/hle/service/psc/time/service_manager.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <list> | ||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | #include "core/hle/service/ipc_helpers.h" | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | #include "core/hle/service/psc/time/manager.h" | ||
| 12 | #include "core/hle/service/server_manager.h" | ||
| 13 | #include "core/hle/service/service.h" | ||
| 14 | |||
| 15 | namespace Core { | ||
| 16 | class System; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Kernel { | ||
| 20 | class KReadableEvent; | ||
| 21 | } | ||
| 22 | |||
| 23 | namespace Service::PSC::Time { | ||
| 24 | class StaticService; | ||
| 25 | |||
| 26 | class ServiceManager final : public ServiceFramework<ServiceManager> { | ||
| 27 | public: | ||
| 28 | explicit ServiceManager(Core::System& system, std::shared_ptr<TimeManager> time, | ||
| 29 | ServerManager* server_manager); | ||
| 30 | ~ServiceManager() override = default; | ||
| 31 | |||
| 32 | Result GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service); | ||
| 33 | Result GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service); | ||
| 34 | Result GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service); | ||
| 35 | Result GetStaticServiceAsServiceManager(std::shared_ptr<StaticService>& out_service); | ||
| 36 | Result SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset, | ||
| 37 | s64 internal_offset, s64 test_offset, | ||
| 38 | bool is_rtc_reset_detected); | ||
| 39 | Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time); | ||
| 40 | Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy); | ||
| 41 | Result SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point, | ||
| 42 | bool automatic_correction); | ||
| 43 | Result SetupTimeZoneServiceCore(LocationName& name, SteadyClockTimePoint& time_point, | ||
| 44 | RuleVersion& rule_version, u32 location_count, | ||
| 45 | std::span<const u8> rule_buffer); | ||
| 46 | Result SetupEphemeralNetworkSystemClockCore(); | ||
| 47 | Result GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event); | ||
| 48 | Result GetStandardNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event); | ||
| 49 | Result GetEphemeralNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event); | ||
| 50 | Result GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(Kernel::KEvent** out_event); | ||
| 51 | Result SetStandardSteadyClockBaseTime(s64 base_time); | ||
| 52 | Result GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event); | ||
| 53 | Result CheckAndSignalAlarms(); | ||
| 54 | Result GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time); | ||
| 55 | |||
| 56 | private: | ||
| 57 | void CheckAndSetupServicesSAndP(); | ||
| 58 | void SetupSAndP(); | ||
| 59 | Result GetStaticService(std::shared_ptr<StaticService>& out_service, | ||
| 60 | StaticServiceSetupInfo setup_info, const char* name); | ||
| 61 | |||
| 62 | void Handle_GetStaticServiceAsUser(HLERequestContext& ctx); | ||
| 63 | void Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx); | ||
| 64 | void Handle_GetStaticServiceAsRepair(HLERequestContext& ctx); | ||
| 65 | void Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx); | ||
| 66 | void Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx); | ||
| 67 | void Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx); | ||
| 68 | void Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx); | ||
| 69 | void Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx); | ||
| 70 | void Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx); | ||
| 71 | void Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx); | ||
| 72 | void Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx); | ||
| 73 | void Handle_GetStandardNetworkClockOperationEventForServiceManager(HLERequestContext& ctx); | ||
| 74 | void Handle_GetEphemeralNetworkClockOperationEventForServiceManager(HLERequestContext& ctx); | ||
| 75 | void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(HLERequestContext& ctx); | ||
| 76 | void Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx); | ||
| 77 | void Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx); | ||
| 78 | void Handle_CheckAndSignalAlarms(HLERequestContext& ctx); | ||
| 79 | void Handle_GetClosestAlarmInfo(HLERequestContext& ctx); | ||
| 80 | |||
| 81 | Core::System& m_system; | ||
| 82 | std::shared_ptr<TimeManager> m_time; | ||
| 83 | ServerManager& m_server_manager; | ||
| 84 | bool m_is_s_and_p_setup{}; | ||
| 85 | StandardLocalSystemClockCore& m_local_system_clock; | ||
| 86 | StandardUserSystemClockCore& m_user_system_clock; | ||
| 87 | StandardNetworkSystemClockCore& m_network_system_clock; | ||
| 88 | StandardSteadyClockCore& m_steady_clock; | ||
| 89 | TimeZone& m_time_zone; | ||
| 90 | EphemeralNetworkSystemClockCore& m_ephemeral_network_clock; | ||
| 91 | SharedMemory& m_shared_memory; | ||
| 92 | Alarms& m_alarms; | ||
| 93 | LocalSystemClockContextWriter& m_local_system_context_writer; | ||
| 94 | NetworkSystemClockContextWriter& m_network_system_context_writer; | ||
| 95 | EphemeralNetworkSystemClockContextWriter& m_ephemeral_system_context_writer; | ||
| 96 | OperationEvent m_local_operation; | ||
| 97 | OperationEvent m_network_operation; | ||
| 98 | OperationEvent m_ephemeral_operation; | ||
| 99 | }; | ||
| 100 | |||
| 101 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/shared_memory.cpp b/src/core/hle/service/psc/time/shared_memory.cpp new file mode 100644 index 000000000..defaceebe --- /dev/null +++ b/src/core/hle/service/psc/time/shared_memory.cpp | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 6 | #include "core/hle/service/psc/time/shared_memory.h" | ||
| 7 | |||
| 8 | namespace Service::PSC::Time { | ||
| 9 | namespace { | ||
| 10 | template <typename T> | ||
| 11 | constexpr inline T ReadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) { | ||
| 12 | while (true) { | ||
| 13 | // Get the counter. | ||
| 14 | auto counter = p->m_counter; | ||
| 15 | |||
| 16 | // Get the value. | ||
| 17 | auto value = p->m_value[counter % 2]; | ||
| 18 | |||
| 19 | // Fence memory. | ||
| 20 | std::atomic_thread_fence(std::memory_order_acquire); | ||
| 21 | |||
| 22 | // Check that the counter matches. | ||
| 23 | if (counter == p->m_counter) { | ||
| 24 | return value; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | template <typename T> | ||
| 30 | constexpr inline void WriteToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) { | ||
| 31 | // Get the current counter. | ||
| 32 | auto counter = p->m_counter; | ||
| 33 | |||
| 34 | // Increment the counter. | ||
| 35 | ++counter; | ||
| 36 | |||
| 37 | // Store the updated value. | ||
| 38 | p->m_value[counter % 2] = value; | ||
| 39 | |||
| 40 | // Fence memory. | ||
| 41 | std::atomic_thread_fence(std::memory_order_release); | ||
| 42 | |||
| 43 | // Set the updated counter. | ||
| 44 | p->m_counter = counter; | ||
| 45 | } | ||
| 46 | } // namespace | ||
| 47 | |||
| 48 | SharedMemory::SharedMemory(Core::System& system) | ||
| 49 | : m_system{system}, m_k_shared_memory{m_system.Kernel().GetTimeSharedMem()}, | ||
| 50 | m_shared_memory_ptr{reinterpret_cast<SharedMemoryStruct*>(m_k_shared_memory.GetPointer())} { | ||
| 51 | std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr)); | ||
| 52 | } | ||
| 53 | |||
| 54 | void SharedMemory::SetLocalSystemContext(SystemClockContext& context) { | ||
| 55 | WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context); | ||
| 56 | } | ||
| 57 | |||
| 58 | void SharedMemory::SetNetworkSystemContext(SystemClockContext& context) { | ||
| 59 | WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context); | ||
| 60 | } | ||
| 61 | |||
| 62 | void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_point) { | ||
| 63 | WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, | ||
| 64 | {time_point, clock_source_id}); | ||
| 65 | } | ||
| 66 | |||
| 67 | void SharedMemory::SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point) { | ||
| 68 | WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point); | ||
| 69 | } | ||
| 70 | |||
| 71 | void SharedMemory::SetAutomaticCorrection(bool automatic_correction) { | ||
| 72 | WriteToLockFreeAtomicType(&m_shared_memory_ptr->automatic_corrections, automatic_correction); | ||
| 73 | } | ||
| 74 | |||
| 75 | void SharedMemory::UpdateBaseTime(s64 time) { | ||
| 76 | SteadyClockTimePoint time_point{ | ||
| 77 | ReadFromLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points)}; | ||
| 78 | |||
| 79 | time_point.time_point = time; | ||
| 80 | |||
| 81 | WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, time_point); | ||
| 82 | } | ||
| 83 | |||
| 84 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/shared_memory.h b/src/core/hle/service/psc/time/shared_memory.h new file mode 100644 index 000000000..f9bf97d5c --- /dev/null +++ b/src/core/hle/service/psc/time/shared_memory.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/service/psc/time/common.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | class KSharedMemory; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::PSC::Time { | ||
| 20 | |||
| 21 | template <typename T> | ||
| 22 | struct LockFreeAtomicType { | ||
| 23 | u32 m_counter; | ||
| 24 | std::array<T, 2> m_value; | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct SharedMemoryStruct { | ||
| 28 | LockFreeAtomicType<SteadyClockTimePoint> steady_time_points; | ||
| 29 | LockFreeAtomicType<SystemClockContext> local_system_clock_contexts; | ||
| 30 | LockFreeAtomicType<SystemClockContext> network_system_clock_contexts; | ||
| 31 | LockFreeAtomicType<bool> automatic_corrections; | ||
| 32 | LockFreeAtomicType<ContinuousAdjustmentTimePoint> continuous_adjustment_time_points; | ||
| 33 | std::array<char, 0xEB8> pad0148; | ||
| 34 | }; | ||
| 35 | static_assert(offsetof(SharedMemoryStruct, steady_time_points) == 0x0, | ||
| 36 | "steady_time_points are in the wrong place!"); | ||
| 37 | static_assert(offsetof(SharedMemoryStruct, local_system_clock_contexts) == 0x38, | ||
| 38 | "local_system_clock_contexts are in the wrong place!"); | ||
| 39 | static_assert(offsetof(SharedMemoryStruct, network_system_clock_contexts) == 0x80, | ||
| 40 | "network_system_clock_contexts are in the wrong place!"); | ||
| 41 | static_assert(offsetof(SharedMemoryStruct, automatic_corrections) == 0xC8, | ||
| 42 | "automatic_corrections are in the wrong place!"); | ||
| 43 | static_assert(offsetof(SharedMemoryStruct, continuous_adjustment_time_points) == 0xD0, | ||
| 44 | "continuous_adjustment_time_points are in the wrong place!"); | ||
| 45 | static_assert(sizeof(SharedMemoryStruct) == 0x1000, | ||
| 46 | "Time's SharedMemoryStruct has the wrong size!"); | ||
| 47 | static_assert(std::is_trivial_v<SharedMemoryStruct>); | ||
| 48 | |||
| 49 | class SharedMemory { | ||
| 50 | public: | ||
| 51 | explicit SharedMemory(Core::System& system); | ||
| 52 | |||
| 53 | Kernel::KSharedMemory& GetKSharedMemory() { | ||
| 54 | return m_k_shared_memory; | ||
| 55 | } | ||
| 56 | |||
| 57 | void SetLocalSystemContext(SystemClockContext& context); | ||
| 58 | void SetNetworkSystemContext(SystemClockContext& context); | ||
| 59 | void SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_diff); | ||
| 60 | void SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point); | ||
| 61 | void SetAutomaticCorrection(bool automatic_correction); | ||
| 62 | void UpdateBaseTime(s64 time); | ||
| 63 | |||
| 64 | private: | ||
| 65 | Core::System& m_system; | ||
| 66 | Kernel::KSharedMemory& m_k_shared_memory; | ||
| 67 | SharedMemoryStruct* m_shared_memory_ptr; | ||
| 68 | }; | ||
| 69 | |||
| 70 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp new file mode 100644 index 000000000..6f8cf3f88 --- /dev/null +++ b/src/core/hle/service/psc/time/static.cpp | |||
| @@ -0,0 +1,500 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 7 | #include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h" | ||
| 8 | #include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" | ||
| 9 | #include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" | ||
| 10 | #include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h" | ||
| 11 | #include "core/hle/service/psc/time/manager.h" | ||
| 12 | #include "core/hle/service/psc/time/shared_memory.h" | ||
| 13 | #include "core/hle/service/psc/time/static.h" | ||
| 14 | #include "core/hle/service/psc/time/steady_clock.h" | ||
| 15 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 16 | #include "core/hle/service/psc/time/time_zone.h" | ||
| 17 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 18 | |||
| 19 | namespace Service::PSC::Time { | ||
| 20 | namespace { | ||
| 21 | constexpr Result GetTimeFromTimePointAndContext(s64* out_time, SteadyClockTimePoint& time_point, | ||
| 22 | SystemClockContext& context) { | ||
| 23 | R_UNLESS(out_time != nullptr, ResultInvalidArgument); | ||
| 24 | R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch); | ||
| 25 | |||
| 26 | *out_time = context.offset + time_point.time_point; | ||
| 27 | R_SUCCEED(); | ||
| 28 | } | ||
| 29 | } // namespace | ||
| 30 | |||
| 31 | StaticService::StaticService(Core::System& system_, StaticServiceSetupInfo setup_info, | ||
| 32 | std::shared_ptr<TimeManager> time, const char* name) | ||
| 33 | : ServiceFramework{system_, name}, m_system{system}, m_setup_info{setup_info}, m_time{time}, | ||
| 34 | m_local_system_clock{m_time->m_standard_local_system_clock}, | ||
| 35 | m_user_system_clock{m_time->m_standard_user_system_clock}, | ||
| 36 | m_network_system_clock{m_time->m_standard_network_system_clock}, | ||
| 37 | m_time_zone{m_time->m_time_zone}, | ||
| 38 | m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, m_shared_memory{ | ||
| 39 | m_time->m_shared_memory} { | ||
| 40 | // clang-format off | ||
| 41 | static const FunctionInfo functions[] = { | ||
| 42 | {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | ||
| 43 | {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | ||
| 44 | {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, | ||
| 45 | {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, | ||
| 46 | {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | ||
| 47 | {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, | ||
| 48 | {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, | ||
| 49 | {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, | ||
| 50 | {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, | ||
| 51 | {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 52 | {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 53 | {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, | ||
| 54 | {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, | ||
| 55 | {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 56 | {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, | ||
| 57 | {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, | ||
| 58 | {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, | ||
| 59 | {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, | ||
| 60 | {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, | ||
| 61 | }; | ||
| 62 | // clang-format on | ||
| 63 | |||
| 64 | RegisterHandlers(functions); | ||
| 65 | } | ||
| 66 | |||
| 67 | Result StaticService::GetClockSnapshotImpl(ClockSnapshot& out_snapshot, | ||
| 68 | SystemClockContext& user_context, | ||
| 69 | SystemClockContext& network_context, TimeType type) { | ||
| 70 | out_snapshot.user_context = user_context; | ||
| 71 | out_snapshot.network_context = network_context; | ||
| 72 | |||
| 73 | R_TRY( | ||
| 74 | m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot.steady_clock_time_point)); | ||
| 75 | |||
| 76 | out_snapshot.is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection(); | ||
| 77 | |||
| 78 | R_TRY(m_time_zone.GetLocationName(out_snapshot.location_name)); | ||
| 79 | |||
| 80 | R_TRY(GetTimeFromTimePointAndContext( | ||
| 81 | &out_snapshot.user_time, out_snapshot.steady_clock_time_point, out_snapshot.user_context)); | ||
| 82 | |||
| 83 | R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.user_calendar_time, | ||
| 84 | out_snapshot.user_calendar_additional_time, | ||
| 85 | out_snapshot.user_time)); | ||
| 86 | |||
| 87 | if (GetTimeFromTimePointAndContext(&out_snapshot.network_time, | ||
| 88 | out_snapshot.steady_clock_time_point, | ||
| 89 | out_snapshot.network_context) != ResultSuccess) { | ||
| 90 | out_snapshot.network_time = 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.network_calendar_time, | ||
| 94 | out_snapshot.network_calendar_additional_time, | ||
| 95 | out_snapshot.network_time)); | ||
| 96 | out_snapshot.type = type; | ||
| 97 | out_snapshot.unk_CE = 0; | ||
| 98 | R_SUCCEED(); | ||
| 99 | } | ||
| 100 | |||
| 101 | void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) { | ||
| 102 | LOG_DEBUG(Service_Time, "called."); | ||
| 103 | |||
| 104 | std::shared_ptr<SystemClock> service{}; | ||
| 105 | auto res = GetStandardUserSystemClock(service); | ||
| 106 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 108 | rb.Push(res); | ||
| 109 | rb.PushIpcInterface<SystemClock>(std::move(service)); | ||
| 110 | } | ||
| 111 | |||
| 112 | void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) { | ||
| 113 | LOG_DEBUG(Service_Time, "called."); | ||
| 114 | |||
| 115 | std::shared_ptr<SystemClock> service{}; | ||
| 116 | auto res = GetStandardNetworkSystemClock(service); | ||
| 117 | |||
| 118 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 119 | rb.Push(res); | ||
| 120 | rb.PushIpcInterface<SystemClock>(std::move(service)); | ||
| 121 | } | ||
| 122 | |||
| 123 | void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) { | ||
| 124 | LOG_DEBUG(Service_Time, "called."); | ||
| 125 | |||
| 126 | std::shared_ptr<SteadyClock> service{}; | ||
| 127 | auto res = GetStandardSteadyClock(service); | ||
| 128 | |||
| 129 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 130 | rb.Push(res); | ||
| 131 | rb.PushIpcInterface(std::move(service)); | ||
| 132 | } | ||
| 133 | |||
| 134 | void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) { | ||
| 135 | LOG_DEBUG(Service_Time, "called."); | ||
| 136 | |||
| 137 | std::shared_ptr<TimeZoneService> service{}; | ||
| 138 | auto res = GetTimeZoneService(service); | ||
| 139 | |||
| 140 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 141 | rb.Push(res); | ||
| 142 | rb.PushIpcInterface(std::move(service)); | ||
| 143 | } | ||
| 144 | |||
| 145 | void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) { | ||
| 146 | LOG_DEBUG(Service_Time, "called."); | ||
| 147 | |||
| 148 | std::shared_ptr<SystemClock> service{}; | ||
| 149 | auto res = GetStandardLocalSystemClock(service); | ||
| 150 | |||
| 151 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 152 | rb.Push(res); | ||
| 153 | rb.PushIpcInterface<SystemClock>(std::move(service)); | ||
| 154 | } | ||
| 155 | |||
| 156 | void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) { | ||
| 157 | LOG_DEBUG(Service_Time, "called."); | ||
| 158 | |||
| 159 | std::shared_ptr<SystemClock> service{}; | ||
| 160 | auto res = GetEphemeralNetworkSystemClock(service); | ||
| 161 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 163 | rb.Push(res); | ||
| 164 | rb.PushIpcInterface<SystemClock>(std::move(service)); | ||
| 165 | } | ||
| 166 | |||
| 167 | void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) { | ||
| 168 | LOG_DEBUG(Service_Time, "called."); | ||
| 169 | |||
| 170 | Kernel::KSharedMemory* shared_memory{}; | ||
| 171 | auto res = GetSharedMemoryNativeHandle(&shared_memory); | ||
| 172 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 174 | rb.Push(res); | ||
| 175 | rb.PushCopyObjects(shared_memory); | ||
| 176 | } | ||
| 177 | |||
| 178 | void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) { | ||
| 179 | LOG_DEBUG(Service_Time, "called."); | ||
| 180 | |||
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 182 | rb.Push(m_setup_info.can_write_steady_clock ? ResultNotImplemented : ResultPermissionDenied); | ||
| 183 | } | ||
| 184 | |||
| 185 | void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) { | ||
| 186 | LOG_DEBUG(Service_Time, "called."); | ||
| 187 | |||
| 188 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 189 | rb.Push(ResultNotImplemented); | ||
| 190 | } | ||
| 191 | |||
| 192 | void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 193 | HLERequestContext& ctx) { | ||
| 194 | LOG_DEBUG(Service_Time, "called."); | ||
| 195 | |||
| 196 | bool is_enabled{}; | ||
| 197 | auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled); | ||
| 198 | |||
| 199 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 200 | rb.Push(res); | ||
| 201 | rb.Push<bool>(is_enabled); | ||
| 202 | } | ||
| 203 | |||
| 204 | void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 205 | HLERequestContext& ctx) { | ||
| 206 | LOG_DEBUG(Service_Time, "called."); | ||
| 207 | |||
| 208 | IPC::RequestParser rp{ctx}; | ||
| 209 | auto automatic_correction{rp.Pop<bool>()}; | ||
| 210 | |||
| 211 | auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction); | ||
| 212 | |||
| 213 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 214 | rb.Push(res); | ||
| 215 | } | ||
| 216 | |||
| 217 | void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) { | ||
| 218 | LOG_DEBUG(Service_Time, "called."); | ||
| 219 | |||
| 220 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 221 | rb.Push(ResultNotImplemented); | ||
| 222 | } | ||
| 223 | |||
| 224 | void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { | ||
| 225 | LOG_DEBUG(Service_Time, "called."); | ||
| 226 | |||
| 227 | bool is_sufficient{}; | ||
| 228 | auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient); | ||
| 229 | |||
| 230 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 231 | rb.Push(res); | ||
| 232 | rb.Push<bool>(is_sufficient); | ||
| 233 | } | ||
| 234 | |||
| 235 | void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 236 | HLERequestContext& ctx) { | ||
| 237 | LOG_DEBUG(Service_Time, "called."); | ||
| 238 | |||
| 239 | SteadyClockTimePoint time_point{}; | ||
| 240 | auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | ||
| 241 | |||
| 242 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)}; | ||
| 243 | rb.Push(res); | ||
| 244 | rb.PushRaw<SteadyClockTimePoint>(time_point); | ||
| 245 | } | ||
| 246 | |||
| 247 | void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { | ||
| 248 | LOG_DEBUG(Service_Time, "called."); | ||
| 249 | |||
| 250 | IPC::RequestParser rp{ctx}; | ||
| 251 | auto context{rp.PopRaw<SystemClockContext>()}; | ||
| 252 | |||
| 253 | s64 time{}; | ||
| 254 | auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context); | ||
| 255 | |||
| 256 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 257 | rb.Push(res); | ||
| 258 | rb.Push<s64>(time); | ||
| 259 | } | ||
| 260 | |||
| 261 | void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { | ||
| 262 | LOG_DEBUG(Service_Time, "called."); | ||
| 263 | |||
| 264 | IPC::RequestParser rp{ctx}; | ||
| 265 | auto type{rp.PopEnum<TimeType>()}; | ||
| 266 | |||
| 267 | ClockSnapshot snapshot{}; | ||
| 268 | auto res = GetClockSnapshot(snapshot, type); | ||
| 269 | |||
| 270 | ctx.WriteBuffer(snapshot); | ||
| 271 | |||
| 272 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 273 | rb.Push(res); | ||
| 274 | } | ||
| 275 | |||
| 276 | void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { | ||
| 277 | LOG_DEBUG(Service_Time, "called."); | ||
| 278 | |||
| 279 | IPC::RequestParser rp{ctx}; | ||
| 280 | auto clock_type{rp.PopEnum<TimeType>()}; | ||
| 281 | [[maybe_unused]] auto alignment{rp.Pop<u32>()}; | ||
| 282 | auto user_context{rp.PopRaw<SystemClockContext>()}; | ||
| 283 | auto network_context{rp.PopRaw<SystemClockContext>()}; | ||
| 284 | |||
| 285 | ClockSnapshot snapshot{}; | ||
| 286 | auto res = | ||
| 287 | GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type); | ||
| 288 | |||
| 289 | ctx.WriteBuffer(snapshot); | ||
| 290 | |||
| 291 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 292 | rb.Push(res); | ||
| 293 | } | ||
| 294 | |||
| 295 | void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( | ||
| 296 | HLERequestContext& ctx) { | ||
| 297 | LOG_DEBUG(Service_Time, "called."); | ||
| 298 | |||
| 299 | ClockSnapshot a{}; | ||
| 300 | ClockSnapshot b{}; | ||
| 301 | |||
| 302 | auto a_buffer{ctx.ReadBuffer(0)}; | ||
| 303 | auto b_buffer{ctx.ReadBuffer(1)}; | ||
| 304 | |||
| 305 | std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot)); | ||
| 306 | std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot)); | ||
| 307 | |||
| 308 | s64 difference{}; | ||
| 309 | auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b); | ||
| 310 | |||
| 311 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 312 | rb.Push(res); | ||
| 313 | rb.Push(difference); | ||
| 314 | } | ||
| 315 | |||
| 316 | void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { | ||
| 317 | LOG_DEBUG(Service_Time, "called."); | ||
| 318 | |||
| 319 | ClockSnapshot a{}; | ||
| 320 | ClockSnapshot b{}; | ||
| 321 | |||
| 322 | auto a_buffer{ctx.ReadBuffer(0)}; | ||
| 323 | auto b_buffer{ctx.ReadBuffer(1)}; | ||
| 324 | |||
| 325 | std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot)); | ||
| 326 | std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot)); | ||
| 327 | |||
| 328 | s64 time{}; | ||
| 329 | auto res = CalculateSpanBetween(time, a, b); | ||
| 330 | |||
| 331 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 332 | rb.Push(res); | ||
| 333 | rb.Push(time); | ||
| 334 | } | ||
| 335 | |||
| 336 | // =============================== Implementations =========================== | ||
| 337 | |||
| 338 | Result StaticService::GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service) { | ||
| 339 | out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock, | ||
| 340 | m_setup_info.can_write_user_clock, | ||
| 341 | m_setup_info.can_write_uninitialized_clock); | ||
| 342 | R_SUCCEED(); | ||
| 343 | } | ||
| 344 | |||
| 345 | Result StaticService::GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) { | ||
| 346 | out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock, | ||
| 347 | m_setup_info.can_write_network_clock, | ||
| 348 | m_setup_info.can_write_uninitialized_clock); | ||
| 349 | R_SUCCEED(); | ||
| 350 | } | ||
| 351 | |||
| 352 | Result StaticService::GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service) { | ||
| 353 | out_service = | ||
| 354 | std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock, | ||
| 355 | m_setup_info.can_write_uninitialized_clock); | ||
| 356 | R_SUCCEED(); | ||
| 357 | } | ||
| 358 | |||
| 359 | Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) { | ||
| 360 | out_service = | ||
| 361 | std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone, | ||
| 362 | m_setup_info.can_write_timezone_device_location); | ||
| 363 | R_SUCCEED(); | ||
| 364 | } | ||
| 365 | |||
| 366 | Result StaticService::GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service) { | ||
| 367 | out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock, | ||
| 368 | m_setup_info.can_write_local_clock, | ||
| 369 | m_setup_info.can_write_uninitialized_clock); | ||
| 370 | R_SUCCEED(); | ||
| 371 | } | ||
| 372 | |||
| 373 | Result StaticService::GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) { | ||
| 374 | out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock, | ||
| 375 | m_setup_info.can_write_network_clock, | ||
| 376 | m_setup_info.can_write_uninitialized_clock); | ||
| 377 | R_SUCCEED(); | ||
| 378 | } | ||
| 379 | |||
| 380 | Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) { | ||
| 381 | *out_shared_memory = &m_shared_memory.GetKSharedMemory(); | ||
| 382 | R_SUCCEED(); | ||
| 383 | } | ||
| 384 | |||
| 385 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled) { | ||
| 386 | R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); | ||
| 387 | |||
| 388 | out_is_enabled = m_user_system_clock.GetAutomaticCorrection(); | ||
| 389 | R_SUCCEED(); | ||
| 390 | } | ||
| 391 | |||
| 392 | Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 393 | bool automatic_correction) { | ||
| 394 | R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(), | ||
| 395 | ResultClockUninitialized); | ||
| 396 | R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied); | ||
| 397 | |||
| 398 | R_TRY(m_user_system_clock.SetAutomaticCorrection(automatic_correction)); | ||
| 399 | |||
| 400 | m_shared_memory.SetAutomaticCorrection(automatic_correction); | ||
| 401 | |||
| 402 | SteadyClockTimePoint time_point{}; | ||
| 403 | R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point)); | ||
| 404 | |||
| 405 | m_user_system_clock.SetTimePointAndSignal(time_point); | ||
| 406 | m_user_system_clock.GetEvent().Signal(); | ||
| 407 | R_SUCCEED(); | ||
| 408 | } | ||
| 409 | |||
| 410 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { | ||
| 411 | out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); | ||
| 412 | R_SUCCEED(); | ||
| 413 | } | ||
| 414 | |||
| 415 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 416 | SteadyClockTimePoint& out_time_point) { | ||
| 417 | R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); | ||
| 418 | |||
| 419 | m_user_system_clock.GetTimePoint(out_time_point); | ||
| 420 | |||
| 421 | R_SUCCEED(); | ||
| 422 | } | ||
| 423 | |||
| 424 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, | ||
| 425 | SystemClockContext& context) { | ||
| 426 | R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); | ||
| 427 | |||
| 428 | SteadyClockTimePoint time_point{}; | ||
| 429 | R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point)); | ||
| 430 | |||
| 431 | R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch); | ||
| 432 | |||
| 433 | auto one_second_ns{ | ||
| 434 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; | ||
| 435 | auto ticks{m_system.CoreTiming().GetClockTicks()}; | ||
| 436 | auto current_time{ConvertToTimeSpan(ticks).count()}; | ||
| 437 | out_time = ((context.offset + time_point.time_point) - (current_time / one_second_ns)); | ||
| 438 | R_SUCCEED(); | ||
| 439 | } | ||
| 440 | |||
| 441 | Result StaticService::GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type) { | ||
| 442 | SystemClockContext user_context{}; | ||
| 443 | R_TRY(m_user_system_clock.GetContext(user_context)); | ||
| 444 | |||
| 445 | SystemClockContext network_context{}; | ||
| 446 | R_TRY(m_network_system_clock.GetContext(network_context)); | ||
| 447 | |||
| 448 | R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); | ||
| 449 | } | ||
| 450 | |||
| 451 | Result StaticService::GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot, | ||
| 452 | SystemClockContext& user_context, | ||
| 453 | SystemClockContext& network_context, | ||
| 454 | TimeType type) { | ||
| 455 | R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); | ||
| 456 | } | ||
| 457 | |||
| 458 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, | ||
| 459 | ClockSnapshot& a, | ||
| 460 | ClockSnapshot& b) { | ||
| 461 | auto diff_s = | ||
| 462 | std::chrono::seconds(b.user_context.offset) - std::chrono::seconds(a.user_context.offset); | ||
| 463 | |||
| 464 | if (a.user_context == b.user_context || | ||
| 465 | !a.user_context.steady_time_point.IdMatches(b.user_context.steady_time_point)) { | ||
| 466 | out_time = 0; | ||
| 467 | R_SUCCEED(); | ||
| 468 | } | ||
| 469 | |||
| 470 | if (!a.is_automatic_correction_enabled || !b.is_automatic_correction_enabled) { | ||
| 471 | out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count(); | ||
| 472 | R_SUCCEED(); | ||
| 473 | } | ||
| 474 | |||
| 475 | if (a.network_context.steady_time_point.IdMatches(a.steady_clock_time_point) || | ||
| 476 | b.network_context.steady_time_point.IdMatches(b.steady_clock_time_point)) { | ||
| 477 | out_time = 0; | ||
| 478 | R_SUCCEED(); | ||
| 479 | } | ||
| 480 | |||
| 481 | out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count(); | ||
| 482 | R_SUCCEED(); | ||
| 483 | } | ||
| 484 | |||
| 485 | Result StaticService::CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b) { | ||
| 486 | s64 time_s{}; | ||
| 487 | auto res = | ||
| 488 | GetSpanBetweenTimePoints(&time_s, a.steady_clock_time_point, b.steady_clock_time_point); | ||
| 489 | |||
| 490 | if (res != ResultSuccess) { | ||
| 491 | R_UNLESS(a.network_time != 0 && b.network_time != 0, ResultTimeNotFound); | ||
| 492 | time_s = b.network_time - a.network_time; | ||
| 493 | } | ||
| 494 | |||
| 495 | out_time = | ||
| 496 | std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count(); | ||
| 497 | R_SUCCEED(); | ||
| 498 | } | ||
| 499 | |||
| 500 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/static.h b/src/core/hle/service/psc/time/static.h new file mode 100644 index 000000000..498cd5ab5 --- /dev/null +++ b/src/core/hle/service/psc/time/static.h | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/psc/time/common.h" | ||
| 8 | #include "core/hle/service/server_manager.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | class KSharedMemory; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Service::PSC::Time { | ||
| 20 | class TimeManager; | ||
| 21 | class StandardLocalSystemClockCore; | ||
| 22 | class StandardUserSystemClockCore; | ||
| 23 | class StandardNetworkSystemClockCore; | ||
| 24 | class TimeZone; | ||
| 25 | class SystemClock; | ||
| 26 | class SteadyClock; | ||
| 27 | class TimeZoneService; | ||
| 28 | class EphemeralNetworkSystemClockCore; | ||
| 29 | class SharedMemory; | ||
| 30 | |||
| 31 | class StaticService final : public ServiceFramework<StaticService> { | ||
| 32 | public: | ||
| 33 | explicit StaticService(Core::System& system, StaticServiceSetupInfo setup_info, | ||
| 34 | std::shared_ptr<TimeManager> time, const char* name); | ||
| 35 | |||
| 36 | ~StaticService() override = default; | ||
| 37 | |||
| 38 | Result GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service); | ||
| 39 | Result GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service); | ||
| 40 | Result GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service); | ||
| 41 | Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service); | ||
| 42 | Result GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service); | ||
| 43 | Result GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service); | ||
| 44 | Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); | ||
| 45 | Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled); | ||
| 46 | Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); | ||
| 47 | Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); | ||
| 48 | Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | ||
| 49 | SteadyClockTimePoint& out_time_point); | ||
| 50 | Result CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, SystemClockContext& context); | ||
| 51 | Result GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type); | ||
| 52 | Result GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot, | ||
| 53 | SystemClockContext& user_context, | ||
| 54 | SystemClockContext& network_context, | ||
| 55 | TimeType type); | ||
| 56 | Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, ClockSnapshot& a, | ||
| 57 | ClockSnapshot& b); | ||
| 58 | Result CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b); | ||
| 59 | |||
| 60 | private: | ||
| 61 | Result GetClockSnapshotImpl(ClockSnapshot& out_snapshot, SystemClockContext& user_context, | ||
| 62 | SystemClockContext& network_context, TimeType type); | ||
| 63 | |||
| 64 | void Handle_GetStandardUserSystemClock(HLERequestContext& ctx); | ||
| 65 | void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx); | ||
| 66 | void Handle_GetStandardSteadyClock(HLERequestContext& ctx); | ||
| 67 | void Handle_GetTimeZoneService(HLERequestContext& ctx); | ||
| 68 | void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx); | ||
| 69 | void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx); | ||
| 70 | void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx); | ||
| 71 | void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx); | ||
| 72 | void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx); | ||
| 73 | void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | ||
| 74 | void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | ||
| 75 | void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx); | ||
| 76 | void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); | ||
| 77 | void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); | ||
| 78 | void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); | ||
| 79 | void Handle_GetClockSnapshot(HLERequestContext& ctx); | ||
| 80 | void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); | ||
| 81 | void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); | ||
| 82 | void Handle_CalculateSpanBetween(HLERequestContext& ctx); | ||
| 83 | |||
| 84 | Core::System& m_system; | ||
| 85 | StaticServiceSetupInfo m_setup_info; | ||
| 86 | std::shared_ptr<TimeManager> m_time; | ||
| 87 | StandardLocalSystemClockCore& m_local_system_clock; | ||
| 88 | StandardUserSystemClockCore& m_user_system_clock; | ||
| 89 | StandardNetworkSystemClockCore& m_network_system_clock; | ||
| 90 | TimeZone& m_time_zone; | ||
| 91 | EphemeralNetworkSystemClockCore& m_ephemeral_network_clock; | ||
| 92 | SharedMemory& m_shared_memory; | ||
| 93 | }; | ||
| 94 | |||
| 95 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp new file mode 100644 index 000000000..1ed5c7679 --- /dev/null +++ b/src/core/hle/service/psc/time/steady_clock.cpp | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/steady_clock.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | |||
| 9 | SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> manager, | ||
| 10 | bool can_write_steady_clock, bool can_write_uninitialized_clock) | ||
| 11 | : ServiceFramework{system_, "ISteadyClock"}, m_system{system}, | ||
| 12 | m_clock_core{manager->m_standard_steady_clock}, | ||
| 13 | m_can_write_steady_clock{can_write_steady_clock}, m_can_write_uninitialized_clock{ | ||
| 14 | can_write_uninitialized_clock} { | ||
| 15 | // clang-format off | ||
| 16 | static const FunctionInfo functions[] = { | ||
| 17 | {0, &SteadyClock::Handle_GetCurrentTimePoint, "GetCurrentTimePoint"}, | ||
| 18 | {2, &SteadyClock::Handle_GetTestOffset, "GetTestOffset"}, | ||
| 19 | {3, &SteadyClock::Handle_SetTestOffset, "SetTestOffset"}, | ||
| 20 | {100, &SteadyClock::Handle_GetRtcValue, "GetRtcValue"}, | ||
| 21 | {101, &SteadyClock::Handle_IsRtcResetDetected, "IsRtcResetDetected"}, | ||
| 22 | {102, &SteadyClock::Handle_GetSetupResultValue, "GetSetupResultValue"}, | ||
| 23 | {200, &SteadyClock::Handle_GetInternalOffset, "GetInternalOffset"}, | ||
| 24 | }; | ||
| 25 | // clang-format on | ||
| 26 | RegisterHandlers(functions); | ||
| 27 | } | ||
| 28 | |||
| 29 | void SteadyClock::Handle_GetCurrentTimePoint(HLERequestContext& ctx) { | ||
| 30 | LOG_DEBUG(Service_Time, "called."); | ||
| 31 | |||
| 32 | SteadyClockTimePoint time_point{}; | ||
| 33 | auto res = GetCurrentTimePoint(time_point); | ||
| 34 | |||
| 35 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)}; | ||
| 36 | rb.Push(res); | ||
| 37 | rb.PushRaw<SteadyClockTimePoint>(time_point); | ||
| 38 | } | ||
| 39 | |||
| 40 | void SteadyClock::Handle_GetTestOffset(HLERequestContext& ctx) { | ||
| 41 | LOG_DEBUG(Service_Time, "called."); | ||
| 42 | |||
| 43 | s64 test_offset{}; | ||
| 44 | auto res = GetTestOffset(test_offset); | ||
| 45 | |||
| 46 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 47 | rb.Push(res); | ||
| 48 | rb.Push(test_offset); | ||
| 49 | } | ||
| 50 | |||
| 51 | void SteadyClock::Handle_SetTestOffset(HLERequestContext& ctx) { | ||
| 52 | LOG_DEBUG(Service_Time, "called."); | ||
| 53 | |||
| 54 | IPC::RequestParser rp{ctx}; | ||
| 55 | auto test_offset{rp.Pop<s64>()}; | ||
| 56 | |||
| 57 | auto res = SetTestOffset(test_offset); | ||
| 58 | |||
| 59 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 60 | rb.Push(res); | ||
| 61 | } | ||
| 62 | |||
| 63 | void SteadyClock::Handle_GetRtcValue(HLERequestContext& ctx) { | ||
| 64 | LOG_DEBUG(Service_Time, "called."); | ||
| 65 | |||
| 66 | s64 rtc_value{}; | ||
| 67 | auto res = GetRtcValue(rtc_value); | ||
| 68 | |||
| 69 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 70 | rb.Push(res); | ||
| 71 | rb.Push(rtc_value); | ||
| 72 | } | ||
| 73 | |||
| 74 | void SteadyClock::Handle_IsRtcResetDetected(HLERequestContext& ctx) { | ||
| 75 | LOG_DEBUG(Service_Time, "called."); | ||
| 76 | |||
| 77 | bool reset_detected{false}; | ||
| 78 | auto res = IsRtcResetDetected(reset_detected); | ||
| 79 | |||
| 80 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 81 | rb.Push(res); | ||
| 82 | rb.Push(reset_detected); | ||
| 83 | } | ||
| 84 | |||
| 85 | void SteadyClock::Handle_GetSetupResultValue(HLERequestContext& ctx) { | ||
| 86 | LOG_DEBUG(Service_Time, "called."); | ||
| 87 | |||
| 88 | Result result_value{ResultSuccess}; | ||
| 89 | auto res = GetSetupResultValue(result_value); | ||
| 90 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 92 | rb.Push(res); | ||
| 93 | rb.Push(result_value); | ||
| 94 | } | ||
| 95 | |||
| 96 | void SteadyClock::Handle_GetInternalOffset(HLERequestContext& ctx) { | ||
| 97 | LOG_DEBUG(Service_Time, "called."); | ||
| 98 | |||
| 99 | s64 internal_offset{}; | ||
| 100 | auto res = GetInternalOffset(internal_offset); | ||
| 101 | |||
| 102 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 103 | rb.Push(res); | ||
| 104 | rb.Push(internal_offset); | ||
| 105 | } | ||
| 106 | |||
| 107 | // =============================== Implementations =========================== | ||
| 108 | |||
| 109 | Result SteadyClock::GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) { | ||
| 110 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 111 | ResultClockUninitialized); | ||
| 112 | |||
| 113 | R_RETURN(m_clock_core.GetCurrentTimePoint(out_time_point)); | ||
| 114 | } | ||
| 115 | |||
| 116 | Result SteadyClock::GetTestOffset(s64& out_test_offset) { | ||
| 117 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 118 | ResultClockUninitialized); | ||
| 119 | |||
| 120 | out_test_offset = m_clock_core.GetTestOffset(); | ||
| 121 | R_SUCCEED(); | ||
| 122 | } | ||
| 123 | |||
| 124 | Result SteadyClock::SetTestOffset(s64 test_offset) { | ||
| 125 | R_UNLESS(m_can_write_steady_clock, ResultPermissionDenied); | ||
| 126 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 127 | ResultClockUninitialized); | ||
| 128 | |||
| 129 | m_clock_core.SetTestOffset(test_offset); | ||
| 130 | R_SUCCEED(); | ||
| 131 | } | ||
| 132 | |||
| 133 | Result SteadyClock::GetRtcValue(s64& out_rtc_value) { | ||
| 134 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 135 | ResultClockUninitialized); | ||
| 136 | |||
| 137 | R_RETURN(m_clock_core.GetRtcValue(out_rtc_value)); | ||
| 138 | } | ||
| 139 | |||
| 140 | Result SteadyClock::IsRtcResetDetected(bool& out_is_detected) { | ||
| 141 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 142 | ResultClockUninitialized); | ||
| 143 | |||
| 144 | out_is_detected = m_clock_core.IsResetDetected(); | ||
| 145 | R_SUCCEED(); | ||
| 146 | } | ||
| 147 | |||
| 148 | Result SteadyClock::GetSetupResultValue(Result& out_result) { | ||
| 149 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 150 | ResultClockUninitialized); | ||
| 151 | |||
| 152 | out_result = m_clock_core.GetSetupResultValue(); | ||
| 153 | R_SUCCEED(); | ||
| 154 | } | ||
| 155 | |||
| 156 | Result SteadyClock::GetInternalOffset(s64& out_internal_offset) { | ||
| 157 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 158 | ResultClockUninitialized); | ||
| 159 | |||
| 160 | out_internal_offset = m_clock_core.GetInternalOffset(); | ||
| 161 | R_SUCCEED(); | ||
| 162 | } | ||
| 163 | |||
| 164 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/steady_clock.h b/src/core/hle/service/psc/time/steady_clock.h new file mode 100644 index 000000000..115e9b138 --- /dev/null +++ b/src/core/hle/service/psc/time/steady_clock.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/psc/time/common.h" | ||
| 8 | #include "core/hle/service/psc/time/manager.h" | ||
| 9 | #include "core/hle/service/server_manager.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::PSC::Time { | ||
| 17 | |||
| 18 | class SteadyClock final : public ServiceFramework<SteadyClock> { | ||
| 19 | public: | ||
| 20 | explicit SteadyClock(Core::System& system, std::shared_ptr<TimeManager> manager, | ||
| 21 | bool can_write_steady_clock, bool can_write_uninitialized_clock); | ||
| 22 | |||
| 23 | ~SteadyClock() override = default; | ||
| 24 | |||
| 25 | Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point); | ||
| 26 | Result GetTestOffset(s64& out_test_offset); | ||
| 27 | Result SetTestOffset(s64 test_offset); | ||
| 28 | Result GetRtcValue(s64& out_rtc_value); | ||
| 29 | Result IsRtcResetDetected(bool& out_is_detected); | ||
| 30 | Result GetSetupResultValue(Result& out_result); | ||
| 31 | Result GetInternalOffset(s64& out_internal_offset); | ||
| 32 | |||
| 33 | private: | ||
| 34 | void Handle_GetCurrentTimePoint(HLERequestContext& ctx); | ||
| 35 | void Handle_GetTestOffset(HLERequestContext& ctx); | ||
| 36 | void Handle_SetTestOffset(HLERequestContext& ctx); | ||
| 37 | void Handle_GetRtcValue(HLERequestContext& ctx); | ||
| 38 | void Handle_IsRtcResetDetected(HLERequestContext& ctx); | ||
| 39 | void Handle_GetSetupResultValue(HLERequestContext& ctx); | ||
| 40 | void Handle_GetInternalOffset(HLERequestContext& ctx); | ||
| 41 | |||
| 42 | Core::System& m_system; | ||
| 43 | |||
| 44 | StandardSteadyClockCore& m_clock_core; | ||
| 45 | bool m_can_write_steady_clock; | ||
| 46 | bool m_can_write_uninitialized_clock; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp new file mode 100644 index 000000000..13d2f1d11 --- /dev/null +++ b/src/core/hle/service/psc/time/system_clock.cpp | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/psc/time/system_clock.h" | ||
| 6 | |||
| 7 | namespace Service::PSC::Time { | ||
| 8 | |||
| 9 | SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, bool can_write_clock, | ||
| 10 | bool can_write_uninitialized_clock) | ||
| 11 | : ServiceFramework{system_, "ISystemClock"}, m_system{system}, m_clock_core{clock_core}, | ||
| 12 | m_can_write_clock{can_write_clock}, m_can_write_uninitialized_clock{ | ||
| 13 | can_write_uninitialized_clock} { | ||
| 14 | // clang-format off | ||
| 15 | static const FunctionInfo functions[] = { | ||
| 16 | {0, &SystemClock::Handle_GetCurrentTime, "GetCurrentTime"}, | ||
| 17 | {1, &SystemClock::Handle_SetCurrentTime, "SetCurrentTime"}, | ||
| 18 | {2, &SystemClock::Handle_GetSystemClockContext, "GetSystemClockContext"}, | ||
| 19 | {3, &SystemClock::Handle_SetSystemClockContext, "SetSystemClockContext"}, | ||
| 20 | {4, &SystemClock::Handle_GetOperationEventReadableHandle, "GetOperationEventReadableHandle"}, | ||
| 21 | }; | ||
| 22 | // clang-format on | ||
| 23 | RegisterHandlers(functions); | ||
| 24 | } | ||
| 25 | |||
| 26 | void SystemClock::Handle_GetCurrentTime(HLERequestContext& ctx) { | ||
| 27 | LOG_DEBUG(Service_Time, "called."); | ||
| 28 | |||
| 29 | s64 time{}; | ||
| 30 | auto res = GetCurrentTime(time); | ||
| 31 | |||
| 32 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 33 | rb.Push(res); | ||
| 34 | rb.Push<s64>(time); | ||
| 35 | } | ||
| 36 | |||
| 37 | void SystemClock::Handle_SetCurrentTime(HLERequestContext& ctx) { | ||
| 38 | LOG_DEBUG(Service_Time, "called."); | ||
| 39 | |||
| 40 | IPC::RequestParser rp{ctx}; | ||
| 41 | auto time{rp.Pop<s64>()}; | ||
| 42 | |||
| 43 | auto res = SetCurrentTime(time); | ||
| 44 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 46 | rb.Push(res); | ||
| 47 | } | ||
| 48 | |||
| 49 | void SystemClock::Handle_GetSystemClockContext(HLERequestContext& ctx) { | ||
| 50 | LOG_DEBUG(Service_Time, "called."); | ||
| 51 | |||
| 52 | SystemClockContext context{}; | ||
| 53 | auto res = GetSystemClockContext(context); | ||
| 54 | |||
| 55 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(SystemClockContext) / sizeof(u32)}; | ||
| 56 | rb.Push(res); | ||
| 57 | rb.PushRaw<SystemClockContext>(context); | ||
| 58 | } | ||
| 59 | |||
| 60 | void SystemClock::Handle_SetSystemClockContext(HLERequestContext& ctx) { | ||
| 61 | LOG_DEBUG(Service_Time, "called."); | ||
| 62 | |||
| 63 | IPC::RequestParser rp{ctx}; | ||
| 64 | auto context{rp.PopRaw<SystemClockContext>()}; | ||
| 65 | |||
| 66 | auto res = SetSystemClockContext(context); | ||
| 67 | |||
| 68 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 69 | rb.Push(res); | ||
| 70 | } | ||
| 71 | |||
| 72 | void SystemClock::Handle_GetOperationEventReadableHandle(HLERequestContext& ctx) { | ||
| 73 | LOG_DEBUG(Service_Time, "called."); | ||
| 74 | |||
| 75 | Kernel::KEvent* event{}; | ||
| 76 | auto res = GetOperationEventReadableHandle(&event); | ||
| 77 | |||
| 78 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 79 | rb.Push(res); | ||
| 80 | rb.PushCopyObjects(event->GetReadableEvent()); | ||
| 81 | } | ||
| 82 | |||
| 83 | // =============================== Implementations =========================== | ||
| 84 | |||
| 85 | Result SystemClock::GetCurrentTime(s64& out_time) { | ||
| 86 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 87 | ResultClockUninitialized); | ||
| 88 | |||
| 89 | R_RETURN(m_clock_core.GetCurrentTime(&out_time)); | ||
| 90 | } | ||
| 91 | |||
| 92 | Result SystemClock::SetCurrentTime(s64 time) { | ||
| 93 | R_UNLESS(m_can_write_clock, ResultPermissionDenied); | ||
| 94 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 95 | ResultClockUninitialized); | ||
| 96 | |||
| 97 | R_RETURN(m_clock_core.SetCurrentTime(time)); | ||
| 98 | } | ||
| 99 | |||
| 100 | Result SystemClock::GetSystemClockContext(SystemClockContext& out_context) { | ||
| 101 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 102 | ResultClockUninitialized); | ||
| 103 | |||
| 104 | R_RETURN(m_clock_core.GetContext(out_context)); | ||
| 105 | } | ||
| 106 | |||
| 107 | Result SystemClock::SetSystemClockContext(SystemClockContext& context) { | ||
| 108 | R_UNLESS(m_can_write_clock, ResultPermissionDenied); | ||
| 109 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | ||
| 110 | ResultClockUninitialized); | ||
| 111 | |||
| 112 | R_RETURN(m_clock_core.SetContextAndWrite(context)); | ||
| 113 | } | ||
| 114 | |||
| 115 | Result SystemClock::GetOperationEventReadableHandle(Kernel::KEvent** out_event) { | ||
| 116 | if (!m_operation_event) { | ||
| 117 | m_operation_event = std::make_unique<OperationEvent>(m_system); | ||
| 118 | R_UNLESS(m_operation_event != nullptr, ResultFailed); | ||
| 119 | |||
| 120 | m_clock_core.LinkOperationEvent(*m_operation_event); | ||
| 121 | } | ||
| 122 | |||
| 123 | *out_event = m_operation_event->m_event; | ||
| 124 | R_SUCCEED(); | ||
| 125 | } | ||
| 126 | |||
| 127 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/system_clock.h b/src/core/hle/service/psc/time/system_clock.h new file mode 100644 index 000000000..f30027e7b --- /dev/null +++ b/src/core/hle/service/psc/time/system_clock.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/psc/time/common.h" | ||
| 8 | #include "core/hle/service/psc/time/manager.h" | ||
| 9 | #include "core/hle/service/server_manager.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::PSC::Time { | ||
| 17 | |||
| 18 | class SystemClock final : public ServiceFramework<SystemClock> { | ||
| 19 | public: | ||
| 20 | explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, | ||
| 21 | bool can_write_clock, bool can_write_uninitialized_clock); | ||
| 22 | |||
| 23 | ~SystemClock() override = default; | ||
| 24 | |||
| 25 | Result GetCurrentTime(s64& out_time); | ||
| 26 | Result SetCurrentTime(s64 time); | ||
| 27 | Result GetSystemClockContext(SystemClockContext& out_context); | ||
| 28 | Result SetSystemClockContext(SystemClockContext& context); | ||
| 29 | Result GetOperationEventReadableHandle(Kernel::KEvent** out_event); | ||
| 30 | |||
| 31 | private: | ||
| 32 | void Handle_GetCurrentTime(HLERequestContext& ctx); | ||
| 33 | void Handle_SetCurrentTime(HLERequestContext& ctx); | ||
| 34 | void Handle_GetSystemClockContext(HLERequestContext& ctx); | ||
| 35 | void Handle_SetSystemClockContext(HLERequestContext& ctx); | ||
| 36 | void Handle_GetOperationEventReadableHandle(HLERequestContext& ctx); | ||
| 37 | |||
| 38 | Core::System& m_system; | ||
| 39 | |||
| 40 | SystemClockCore& m_clock_core; | ||
| 41 | bool m_can_write_clock; | ||
| 42 | bool m_can_write_uninitialized_clock; | ||
| 43 | std::unique_ptr<OperationEvent> m_operation_event{}; | ||
| 44 | }; | ||
| 45 | |||
| 46 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/time_zone.cpp b/src/core/hle/service/psc/time/time_zone.cpp new file mode 100644 index 000000000..cfee8f866 --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone.cpp | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/psc/time/time_zone.h" | ||
| 5 | |||
| 6 | namespace Service::PSC::Time { | ||
| 7 | namespace { | ||
| 8 | constexpr Result ValidateRule(Tz::Rule& rule) { | ||
| 9 | if (rule.typecnt > static_cast<s32>(Tz::TZ_MAX_TYPES) || | ||
| 10 | rule.timecnt > static_cast<s32>(Tz::TZ_MAX_TIMES) || | ||
| 11 | rule.charcnt > static_cast<s32>(Tz::TZ_MAX_CHARS)) { | ||
| 12 | R_RETURN(ResultTimeZoneOutOfRange); | ||
| 13 | } | ||
| 14 | |||
| 15 | for (s32 i = 0; i < rule.timecnt; i++) { | ||
| 16 | if (rule.types[i] >= rule.typecnt) { | ||
| 17 | R_RETURN(ResultTimeZoneOutOfRange); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | for (s32 i = 0; i < rule.typecnt; i++) { | ||
| 22 | if (rule.ttis[i].tt_desigidx >= static_cast<s32>(rule.chars.size())) { | ||
| 23 | R_RETURN(ResultTimeZoneOutOfRange); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | R_SUCCEED(); | ||
| 27 | } | ||
| 28 | |||
| 29 | constexpr bool GetTimeZoneTime(s64& out_time, Tz::Rule& rule, s64 time, s32 index, | ||
| 30 | s32 index_offset) { | ||
| 31 | s32 found_idx{}; | ||
| 32 | s32 expected_index{index + index_offset}; | ||
| 33 | s64 time_to_find{time + rule.ttis[rule.types[index]].tt_utoff - | ||
| 34 | rule.ttis[rule.types[expected_index]].tt_utoff}; | ||
| 35 | |||
| 36 | if (rule.timecnt > 1 && rule.ats[0] <= time_to_find) { | ||
| 37 | s32 low{1}; | ||
| 38 | s32 high{rule.timecnt}; | ||
| 39 | |||
| 40 | while (low < high) { | ||
| 41 | auto mid{(low + high) / 2}; | ||
| 42 | if (rule.ats[mid] <= time_to_find) { | ||
| 43 | low = mid + 1; | ||
| 44 | } else if (rule.ats[mid] > time_to_find) { | ||
| 45 | high = mid; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | found_idx = low - 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | if (found_idx == expected_index) { | ||
| 52 | out_time = time_to_find; | ||
| 53 | } | ||
| 54 | return found_idx == expected_index; | ||
| 55 | } | ||
| 56 | } // namespace | ||
| 57 | |||
| 58 | void TimeZone::SetTimePoint(SteadyClockTimePoint& time_point) { | ||
| 59 | std::scoped_lock l{m_mutex}; | ||
| 60 | m_steady_clock_time_point = time_point; | ||
| 61 | } | ||
| 62 | |||
| 63 | void TimeZone::SetTotalLocationNameCount(u32 count) { | ||
| 64 | std::scoped_lock l{m_mutex}; | ||
| 65 | m_total_location_name_count = count; | ||
| 66 | } | ||
| 67 | |||
| 68 | void TimeZone::SetRuleVersion(RuleVersion& rule_version) { | ||
| 69 | std::scoped_lock l{m_mutex}; | ||
| 70 | m_rule_version = rule_version; | ||
| 71 | } | ||
| 72 | |||
| 73 | Result TimeZone::GetLocationName(LocationName& out_name) { | ||
| 74 | std::scoped_lock l{m_mutex}; | ||
| 75 | R_UNLESS(m_initialized, ResultClockUninitialized); | ||
| 76 | out_name = m_location; | ||
| 77 | R_SUCCEED(); | ||
| 78 | } | ||
| 79 | |||
| 80 | Result TimeZone::GetTotalLocationCount(u32& out_count) { | ||
| 81 | std::scoped_lock l{m_mutex}; | ||
| 82 | if (!m_initialized) { | ||
| 83 | return ResultClockUninitialized; | ||
| 84 | } | ||
| 85 | |||
| 86 | out_count = m_total_location_name_count; | ||
| 87 | R_SUCCEED(); | ||
| 88 | } | ||
| 89 | |||
| 90 | Result TimeZone::GetRuleVersion(RuleVersion& out_rule_version) { | ||
| 91 | std::scoped_lock l{m_mutex}; | ||
| 92 | if (!m_initialized) { | ||
| 93 | return ResultClockUninitialized; | ||
| 94 | } | ||
| 95 | out_rule_version = m_rule_version; | ||
| 96 | R_SUCCEED(); | ||
| 97 | } | ||
| 98 | |||
| 99 | Result TimeZone::GetTimePoint(SteadyClockTimePoint& out_time_point) { | ||
| 100 | std::scoped_lock l{m_mutex}; | ||
| 101 | if (!m_initialized) { | ||
| 102 | return ResultClockUninitialized; | ||
| 103 | } | ||
| 104 | out_time_point = m_steady_clock_time_point; | ||
| 105 | R_SUCCEED(); | ||
| 106 | } | ||
| 107 | |||
| 108 | Result TimeZone::ToCalendarTime(CalendarTime& out_calendar_time, | ||
| 109 | CalendarAdditionalInfo& out_additional_info, s64 time, | ||
| 110 | Tz::Rule& rule) { | ||
| 111 | std::scoped_lock l{m_mutex}; | ||
| 112 | R_RETURN(ToCalendarTimeImpl(out_calendar_time, out_additional_info, time, rule)); | ||
| 113 | } | ||
| 114 | |||
| 115 | Result TimeZone::ToCalendarTimeWithMyRule(CalendarTime& calendar_time, | ||
| 116 | CalendarAdditionalInfo& calendar_additional, s64 time) { | ||
| 117 | // This is checked outside the mutex. Bug? | ||
| 118 | if (!m_initialized) { | ||
| 119 | return ResultClockUninitialized; | ||
| 120 | } | ||
| 121 | |||
| 122 | std::scoped_lock l{m_mutex}; | ||
| 123 | R_RETURN(ToCalendarTimeImpl(calendar_time, calendar_additional, time, m_my_rule)); | ||
| 124 | } | ||
| 125 | |||
| 126 | Result TimeZone::ParseBinary(LocationName& name, std::span<const u8> binary) { | ||
| 127 | std::scoped_lock l{m_mutex}; | ||
| 128 | |||
| 129 | Tz::Rule tmp_rule{}; | ||
| 130 | R_TRY(ParseBinaryImpl(tmp_rule, binary)); | ||
| 131 | |||
| 132 | m_my_rule = tmp_rule; | ||
| 133 | m_location = name; | ||
| 134 | |||
| 135 | R_SUCCEED(); | ||
| 136 | } | ||
| 137 | |||
| 138 | Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary) { | ||
| 139 | std::scoped_lock l{m_mutex}; | ||
| 140 | R_RETURN(ParseBinaryImpl(out_rule, binary)); | ||
| 141 | } | ||
| 142 | |||
| 143 | Result TimeZone::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 144 | CalendarTime& calendar, Tz::Rule& rule) { | ||
| 145 | std::scoped_lock l{m_mutex}; | ||
| 146 | |||
| 147 | auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1); | ||
| 148 | |||
| 149 | if (res != ResultSuccess) { | ||
| 150 | if (res == ResultTimeZoneNotFound) { | ||
| 151 | res = ResultSuccess; | ||
| 152 | out_count = 0; | ||
| 153 | } | ||
| 154 | } else if (out_count == 2 && out_times[0] > out_times[1]) { | ||
| 155 | std::swap(out_times[0], out_times[1]); | ||
| 156 | } | ||
| 157 | R_RETURN(res); | ||
| 158 | } | ||
| 159 | |||
| 160 | Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, | ||
| 161 | u32 out_times_count, CalendarTime& calendar) { | ||
| 162 | std::scoped_lock l{m_mutex}; | ||
| 163 | |||
| 164 | auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1); | ||
| 165 | |||
| 166 | if (res != ResultSuccess) { | ||
| 167 | if (res == ResultTimeZoneNotFound) { | ||
| 168 | res = ResultSuccess; | ||
| 169 | out_count = 0; | ||
| 170 | } | ||
| 171 | } else if (out_count == 2 && out_times[0] > out_times[1]) { | ||
| 172 | std::swap(out_times[0], out_times[1]); | ||
| 173 | } | ||
| 174 | R_RETURN(res); | ||
| 175 | } | ||
| 176 | |||
| 177 | Result TimeZone::ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary) { | ||
| 178 | if (Tz::ParseTimeZoneBinary(out_rule, binary)) { | ||
| 179 | R_RETURN(ResultTimeZoneParseFailed); | ||
| 180 | } | ||
| 181 | R_SUCCEED(); | ||
| 182 | } | ||
| 183 | |||
| 184 | Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time, | ||
| 185 | CalendarAdditionalInfo& out_additional_info, s64 time, | ||
| 186 | Tz::Rule& rule) { | ||
| 187 | R_TRY(ValidateRule(rule)); | ||
| 188 | |||
| 189 | Tz::CalendarTimeInternal calendar_internal{}; | ||
| 190 | time_t time_tmp{static_cast<time_t>(time)}; | ||
| 191 | if (Tz::localtime_rz(&calendar_internal, &rule, &time_tmp)) { | ||
| 192 | R_RETURN(ResultOverflow); | ||
| 193 | } | ||
| 194 | |||
| 195 | out_calendar_time.year = static_cast<s16>(calendar_internal.tm_year + 1900); | ||
| 196 | out_calendar_time.month = static_cast<s8>(calendar_internal.tm_mon + 1); | ||
| 197 | out_calendar_time.day = static_cast<s8>(calendar_internal.tm_mday); | ||
| 198 | out_calendar_time.hour = static_cast<s8>(calendar_internal.tm_hour); | ||
| 199 | out_calendar_time.minute = static_cast<s8>(calendar_internal.tm_min); | ||
| 200 | out_calendar_time.second = static_cast<s8>(calendar_internal.tm_sec); | ||
| 201 | |||
| 202 | out_additional_info.day_of_week = calendar_internal.tm_wday; | ||
| 203 | out_additional_info.day_of_year = calendar_internal.tm_yday; | ||
| 204 | |||
| 205 | std::memcpy(out_additional_info.name.data(), calendar_internal.tm_zone.data(), | ||
| 206 | out_additional_info.name.size()); | ||
| 207 | out_additional_info.name[out_additional_info.name.size() - 1] = '\0'; | ||
| 208 | |||
| 209 | out_additional_info.is_dst = calendar_internal.tm_isdst; | ||
| 210 | out_additional_info.ut_offset = calendar_internal.tm_utoff; | ||
| 211 | |||
| 212 | R_SUCCEED(); | ||
| 213 | } | ||
| 214 | |||
| 215 | Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 216 | CalendarTime& calendar, Tz::Rule& rule, s32 is_dst) { | ||
| 217 | R_TRY(ValidateRule(rule)); | ||
| 218 | |||
| 219 | calendar.month -= 1; | ||
| 220 | calendar.year -= 1900; | ||
| 221 | |||
| 222 | Tz::CalendarTimeInternal internal{ | ||
| 223 | .tm_sec = calendar.second, | ||
| 224 | .tm_min = calendar.minute, | ||
| 225 | .tm_hour = calendar.hour, | ||
| 226 | .tm_mday = calendar.day, | ||
| 227 | .tm_mon = calendar.month, | ||
| 228 | .tm_year = calendar.year, | ||
| 229 | .tm_wday = 0, | ||
| 230 | .tm_yday = 0, | ||
| 231 | .tm_isdst = is_dst, | ||
| 232 | .tm_zone = {}, | ||
| 233 | .tm_utoff = 0, | ||
| 234 | .time_index = 0, | ||
| 235 | }; | ||
| 236 | time_t time_tmp{}; | ||
| 237 | auto res = Tz::mktime_tzname(&time_tmp, &rule, &internal); | ||
| 238 | s64 time = static_cast<s64>(time_tmp); | ||
| 239 | |||
| 240 | if (res == 1) { | ||
| 241 | R_RETURN(ResultOverflow); | ||
| 242 | } else if (res == 2) { | ||
| 243 | R_RETURN(ResultTimeZoneNotFound); | ||
| 244 | } | ||
| 245 | |||
| 246 | if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute || | ||
| 247 | internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day || | ||
| 248 | internal.tm_mon != calendar.month || internal.tm_year != calendar.year) { | ||
| 249 | R_RETURN(ResultTimeZoneNotFound); | ||
| 250 | } | ||
| 251 | |||
| 252 | if (res != 0) { | ||
| 253 | ASSERT(false); | ||
| 254 | } | ||
| 255 | |||
| 256 | out_times[0] = time; | ||
| 257 | if (out_times_count < 2) { | ||
| 258 | out_count = 1; | ||
| 259 | R_SUCCEED(); | ||
| 260 | } | ||
| 261 | |||
| 262 | s64 time2{}; | ||
| 263 | if (internal.time_index > 0 && GetTimeZoneTime(time2, rule, time, internal.time_index, -1)) { | ||
| 264 | out_times[1] = time2; | ||
| 265 | out_count = 2; | ||
| 266 | R_SUCCEED(); | ||
| 267 | } | ||
| 268 | |||
| 269 | if (((internal.time_index + 1) < rule.timecnt) && | ||
| 270 | GetTimeZoneTime(time2, rule, time, internal.time_index, 1)) { | ||
| 271 | out_times[1] = time2; | ||
| 272 | out_count = 2; | ||
| 273 | R_SUCCEED(); | ||
| 274 | } | ||
| 275 | |||
| 276 | out_count = 1; | ||
| 277 | R_SUCCEED(); | ||
| 278 | } | ||
| 279 | |||
| 280 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/time_zone.h b/src/core/hle/service/psc/time/time_zone.h new file mode 100644 index 000000000..ce2acca17 --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | #include <span> | ||
| 8 | |||
| 9 | #include <tz/tz.h> | ||
| 10 | #include "core/hle/service/psc/time/common.h" | ||
| 11 | |||
| 12 | namespace Service::PSC::Time { | ||
| 13 | |||
| 14 | class TimeZone { | ||
| 15 | public: | ||
| 16 | TimeZone() = default; | ||
| 17 | |||
| 18 | bool IsInitialized() const { | ||
| 19 | return m_initialized; | ||
| 20 | } | ||
| 21 | |||
| 22 | void SetInitialized() { | ||
| 23 | m_initialized = true; | ||
| 24 | } | ||
| 25 | |||
| 26 | void SetTimePoint(SteadyClockTimePoint& time_point); | ||
| 27 | void SetTotalLocationNameCount(u32 count); | ||
| 28 | void SetRuleVersion(RuleVersion& rule_version); | ||
| 29 | Result GetLocationName(LocationName& out_name); | ||
| 30 | Result GetTotalLocationCount(u32& out_count); | ||
| 31 | Result GetRuleVersion(RuleVersion& out_rule_version); | ||
| 32 | Result GetTimePoint(SteadyClockTimePoint& out_time_point); | ||
| 33 | |||
| 34 | Result ToCalendarTime(CalendarTime& out_calendar_time, | ||
| 35 | CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule); | ||
| 36 | Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time, | ||
| 37 | CalendarAdditionalInfo& calendar_additional, s64 time); | ||
| 38 | Result ParseBinary(LocationName& name, std::span<const u8> binary); | ||
| 39 | Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary); | ||
| 40 | Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 41 | CalendarTime& calendar, Tz::Rule& rule); | ||
| 42 | Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 43 | CalendarTime& calendar); | ||
| 44 | |||
| 45 | private: | ||
| 46 | Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary); | ||
| 47 | Result ToCalendarTimeImpl(CalendarTime& out_calendar_time, | ||
| 48 | CalendarAdditionalInfo& out_additional_info, s64 time, | ||
| 49 | Tz::Rule& rule); | ||
| 50 | Result ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 51 | CalendarTime& calendar, Tz::Rule& rule, s32 is_dst); | ||
| 52 | |||
| 53 | bool m_initialized{}; | ||
| 54 | std::recursive_mutex m_mutex; | ||
| 55 | LocationName m_location{}; | ||
| 56 | Tz::Rule m_my_rule{}; | ||
| 57 | SteadyClockTimePoint m_steady_clock_time_point{}; | ||
| 58 | u32 m_total_location_name_count{}; | ||
| 59 | RuleVersion m_rule_version{}; | ||
| 60 | }; | ||
| 61 | |||
| 62 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp new file mode 100644 index 000000000..e304c8387 --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone_service.cpp | |||
| @@ -0,0 +1,289 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <tz/tz.h> | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hle/service/psc/time/time_zone_service.h" | ||
| 7 | |||
| 8 | namespace Service::PSC::Time { | ||
| 9 | |||
| 10 | TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore& clock_core, | ||
| 11 | TimeZone& time_zone, bool can_write_timezone_device_location) | ||
| 12 | : ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, m_clock_core{clock_core}, | ||
| 13 | m_time_zone{time_zone}, m_can_write_timezone_device_location{ | ||
| 14 | can_write_timezone_device_location} { | ||
| 15 | // clang-format off | ||
| 16 | static const FunctionInfo functions[] = { | ||
| 17 | {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, | ||
| 18 | {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, | ||
| 19 | {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, | ||
| 20 | {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, | ||
| 21 | {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, | ||
| 22 | {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, | ||
| 23 | {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, | ||
| 24 | {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, | ||
| 25 | {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, | ||
| 26 | {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, | ||
| 27 | {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, | ||
| 28 | {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | ||
| 29 | {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, | ||
| 30 | {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, | ||
| 31 | }; | ||
| 32 | // clang-format on | ||
| 33 | RegisterHandlers(functions); | ||
| 34 | } | ||
| 35 | |||
| 36 | void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { | ||
| 37 | LOG_DEBUG(Service_Time, "called."); | ||
| 38 | |||
| 39 | LocationName name{}; | ||
| 40 | auto res = GetDeviceLocationName(name); | ||
| 41 | |||
| 42 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(LocationName) / sizeof(u32)}; | ||
| 43 | rb.Push(res); | ||
| 44 | rb.PushRaw<LocationName>(name); | ||
| 45 | } | ||
| 46 | |||
| 47 | void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) { | ||
| 48 | LOG_DEBUG(Service_Time, "called."); | ||
| 49 | |||
| 50 | IPC::RequestParser rp{ctx}; | ||
| 51 | [[maybe_unused]] auto name{rp.PopRaw<LocationName>()}; | ||
| 52 | |||
| 53 | if (!m_can_write_timezone_device_location) { | ||
| 54 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 55 | rb.Push(ResultPermissionDenied); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 60 | rb.Push(ResultNotImplemented); | ||
| 61 | } | ||
| 62 | |||
| 63 | void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) { | ||
| 64 | LOG_DEBUG(Service_Time, "called."); | ||
| 65 | |||
| 66 | u32 count{}; | ||
| 67 | auto res = GetTotalLocationNameCount(count); | ||
| 68 | |||
| 69 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 70 | rb.Push(res); | ||
| 71 | rb.Push(count); | ||
| 72 | } | ||
| 73 | |||
| 74 | void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) { | ||
| 75 | LOG_DEBUG(Service_Time, "called."); | ||
| 76 | |||
| 77 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 78 | rb.Push(ResultNotImplemented); | ||
| 79 | } | ||
| 80 | |||
| 81 | void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) { | ||
| 82 | LOG_DEBUG(Service_Time, "called."); | ||
| 83 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 85 | rb.Push(ResultNotImplemented); | ||
| 86 | } | ||
| 87 | |||
| 88 | void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) { | ||
| 89 | LOG_DEBUG(Service_Time, "called."); | ||
| 90 | |||
| 91 | RuleVersion rule_version{}; | ||
| 92 | auto res = GetTimeZoneRuleVersion(rule_version); | ||
| 93 | |||
| 94 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(RuleVersion) / sizeof(u32)}; | ||
| 95 | rb.Push(res); | ||
| 96 | rb.PushRaw<RuleVersion>(rule_version); | ||
| 97 | } | ||
| 98 | |||
| 99 | void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) { | ||
| 100 | LOG_DEBUG(Service_Time, "called."); | ||
| 101 | |||
| 102 | LocationName name{}; | ||
| 103 | SteadyClockTimePoint time_point{}; | ||
| 104 | auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name); | ||
| 105 | |||
| 106 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(LocationName) / sizeof(u32)) + | ||
| 107 | (sizeof(SteadyClockTimePoint) / sizeof(u32))}; | ||
| 108 | rb.Push(res); | ||
| 109 | rb.PushRaw<LocationName>(name); | ||
| 110 | rb.PushRaw<SteadyClockTimePoint>(time_point); | ||
| 111 | } | ||
| 112 | |||
| 113 | void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) { | ||
| 114 | LOG_DEBUG(Service_Time, "called."); | ||
| 115 | |||
| 116 | IPC::RequestParser rp{ctx}; | ||
| 117 | auto name{rp.PopRaw<LocationName>()}; | ||
| 118 | |||
| 119 | auto binary{ctx.ReadBuffer()}; | ||
| 120 | auto res = SetDeviceLocationNameWithTimeZoneRule(name, binary); | ||
| 121 | |||
| 122 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 123 | rb.Push(res); | ||
| 124 | } | ||
| 125 | |||
| 126 | void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) { | ||
| 127 | LOG_DEBUG(Service_Time, "called."); | ||
| 128 | |||
| 129 | auto binary{ctx.ReadBuffer()}; | ||
| 130 | |||
| 131 | Tz::Rule rule{}; | ||
| 132 | auto res = ParseTimeZoneBinary(rule, binary); | ||
| 133 | |||
| 134 | ctx.WriteBuffer(rule); | ||
| 135 | |||
| 136 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 137 | rb.Push(res); | ||
| 138 | } | ||
| 139 | |||
| 140 | void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle( | ||
| 141 | HLERequestContext& ctx) { | ||
| 142 | LOG_DEBUG(Service_Time, "called."); | ||
| 143 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 145 | rb.Push(ResultNotImplemented); | ||
| 146 | } | ||
| 147 | |||
| 148 | void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) { | ||
| 149 | LOG_DEBUG(Service_Time, "called."); | ||
| 150 | |||
| 151 | IPC::RequestParser rp{ctx}; | ||
| 152 | auto time{rp.Pop<s64>()}; | ||
| 153 | |||
| 154 | auto rule_buffer{ctx.ReadBuffer()}; | ||
| 155 | Tz::Rule rule{}; | ||
| 156 | std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule)); | ||
| 157 | |||
| 158 | CalendarTime calendar_time{}; | ||
| 159 | CalendarAdditionalInfo additional_info{}; | ||
| 160 | auto res = ToCalendarTime(calendar_time, additional_info, time, rule); | ||
| 161 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) + | ||
| 163 | (sizeof(CalendarAdditionalInfo) / sizeof(u32))}; | ||
| 164 | rb.Push(res); | ||
| 165 | rb.PushRaw<CalendarTime>(calendar_time); | ||
| 166 | rb.PushRaw<CalendarAdditionalInfo>(additional_info); | ||
| 167 | } | ||
| 168 | |||
| 169 | void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) { | ||
| 170 | LOG_DEBUG(Service_Time, "called."); | ||
| 171 | |||
| 172 | IPC::RequestParser rp{ctx}; | ||
| 173 | auto time{rp.Pop<s64>()}; | ||
| 174 | |||
| 175 | CalendarTime calendar_time{}; | ||
| 176 | CalendarAdditionalInfo additional_info{}; | ||
| 177 | auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time); | ||
| 178 | |||
| 179 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) + | ||
| 180 | (sizeof(CalendarAdditionalInfo) / sizeof(u32))}; | ||
| 181 | rb.Push(res); | ||
| 182 | rb.PushRaw<CalendarTime>(calendar_time); | ||
| 183 | rb.PushRaw<CalendarAdditionalInfo>(additional_info); | ||
| 184 | } | ||
| 185 | |||
| 186 | void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) { | ||
| 187 | LOG_DEBUG(Service_Time, "called."); | ||
| 188 | |||
| 189 | IPC::RequestParser rp{ctx}; | ||
| 190 | auto calendar{rp.PopRaw<CalendarTime>()}; | ||
| 191 | |||
| 192 | auto binary{ctx.ReadBuffer()}; | ||
| 193 | |||
| 194 | Tz::Rule rule{}; | ||
| 195 | std::memcpy(&rule, binary.data(), sizeof(Tz::Rule)); | ||
| 196 | |||
| 197 | u32 count{}; | ||
| 198 | std::array<s64, 2> times{}; | ||
| 199 | u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; | ||
| 200 | |||
| 201 | auto res = ToPosixTime(count, times, times_count, calendar, rule); | ||
| 202 | |||
| 203 | ctx.WriteBuffer(times); | ||
| 204 | |||
| 205 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 206 | rb.Push(res); | ||
| 207 | rb.Push(count); | ||
| 208 | } | ||
| 209 | |||
| 210 | void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) { | ||
| 211 | LOG_DEBUG(Service_Time, "called."); | ||
| 212 | |||
| 213 | IPC::RequestParser rp{ctx}; | ||
| 214 | auto calendar{rp.PopRaw<CalendarTime>()}; | ||
| 215 | |||
| 216 | u32 count{}; | ||
| 217 | std::array<s64, 2> times{}; | ||
| 218 | u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; | ||
| 219 | |||
| 220 | auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar); | ||
| 221 | |||
| 222 | ctx.WriteBuffer(times); | ||
| 223 | |||
| 224 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 225 | rb.Push(res); | ||
| 226 | rb.Push(count); | ||
| 227 | } | ||
| 228 | |||
| 229 | // =============================== Implementations =========================== | ||
| 230 | |||
| 231 | Result TimeZoneService::GetDeviceLocationName(LocationName& out_location_name) { | ||
| 232 | R_RETURN(m_time_zone.GetLocationName(out_location_name)); | ||
| 233 | } | ||
| 234 | |||
| 235 | Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { | ||
| 236 | R_RETURN(m_time_zone.GetTotalLocationCount(out_count)); | ||
| 237 | } | ||
| 238 | |||
| 239 | Result TimeZoneService::GetTimeZoneRuleVersion(RuleVersion& out_rule_version) { | ||
| 240 | R_RETURN(m_time_zone.GetRuleVersion(out_rule_version)); | ||
| 241 | } | ||
| 242 | |||
| 243 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point, | ||
| 244 | LocationName& location_name) { | ||
| 245 | R_TRY(m_time_zone.GetLocationName(location_name)); | ||
| 246 | R_RETURN(m_time_zone.GetTimePoint(out_time_point)); | ||
| 247 | } | ||
| 248 | |||
| 249 | Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name, | ||
| 250 | std::span<const u8> binary) { | ||
| 251 | R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied); | ||
| 252 | R_TRY(m_time_zone.ParseBinary(location_name, binary)); | ||
| 253 | |||
| 254 | SteadyClockTimePoint time_point{}; | ||
| 255 | R_TRY(m_clock_core.GetCurrentTimePoint(time_point)); | ||
| 256 | |||
| 257 | m_time_zone.SetTimePoint(time_point); | ||
| 258 | R_SUCCEED(); | ||
| 259 | } | ||
| 260 | |||
| 261 | Result TimeZoneService::ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary) { | ||
| 262 | R_RETURN(m_time_zone.ParseBinaryInto(out_rule, binary)); | ||
| 263 | } | ||
| 264 | |||
| 265 | Result TimeZoneService::ToCalendarTime(CalendarTime& out_calendar_time, | ||
| 266 | CalendarAdditionalInfo& out_additional_info, s64 time, | ||
| 267 | Tz::Rule& rule) { | ||
| 268 | R_RETURN(m_time_zone.ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); | ||
| 269 | } | ||
| 270 | |||
| 271 | Result TimeZoneService::ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time, | ||
| 272 | CalendarAdditionalInfo& out_additional_info, | ||
| 273 | s64 time) { | ||
| 274 | R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); | ||
| 275 | } | ||
| 276 | |||
| 277 | Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, | ||
| 278 | u32 out_times_count, CalendarTime& calendar_time, | ||
| 279 | Tz::Rule& rule) { | ||
| 280 | R_RETURN(m_time_zone.ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); | ||
| 281 | } | ||
| 282 | |||
| 283 | Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, | ||
| 284 | u32 out_times_count, CalendarTime& calendar_time) { | ||
| 285 | R_RETURN( | ||
| 286 | m_time_zone.ToPosixTimeWithMyRule(out_count, out_times, out_times_count, calendar_time)); | ||
| 287 | } | ||
| 288 | |||
| 289 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/psc/time/time_zone_service.h b/src/core/hle/service/psc/time/time_zone_service.h new file mode 100644 index 000000000..074c1d4ae --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone_service.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/psc/time/common.h" | ||
| 8 | #include "core/hle/service/psc/time/manager.h" | ||
| 9 | #include "core/hle/service/server_manager.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Tz { | ||
| 17 | struct Rule; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::PSC::Time { | ||
| 21 | |||
| 22 | class TimeZoneService final : public ServiceFramework<TimeZoneService> { | ||
| 23 | public: | ||
| 24 | explicit TimeZoneService(Core::System& system, StandardSteadyClockCore& clock_core, | ||
| 25 | TimeZone& time_zone, bool can_write_timezone_device_location); | ||
| 26 | |||
| 27 | ~TimeZoneService() override = default; | ||
| 28 | |||
| 29 | Result GetDeviceLocationName(LocationName& out_location_name); | ||
| 30 | Result GetTotalLocationNameCount(u32& out_count); | ||
| 31 | Result GetTimeZoneRuleVersion(RuleVersion& out_rule_version); | ||
| 32 | Result GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point, | ||
| 33 | LocationName& location_name); | ||
| 34 | Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name, | ||
| 35 | std::span<const u8> binary); | ||
| 36 | Result ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary); | ||
| 37 | Result ToCalendarTime(CalendarTime& out_calendar_time, | ||
| 38 | CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule); | ||
| 39 | Result ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time, | ||
| 40 | CalendarAdditionalInfo& out_additional_info, s64 time); | ||
| 41 | Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 42 | CalendarTime& calendar_time, Tz::Rule& rule); | ||
| 43 | Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, | ||
| 44 | CalendarTime& calendar_time); | ||
| 45 | |||
| 46 | private: | ||
| 47 | void Handle_GetDeviceLocationName(HLERequestContext& ctx); | ||
| 48 | void Handle_SetDeviceLocationName(HLERequestContext& ctx); | ||
| 49 | void Handle_GetTotalLocationNameCount(HLERequestContext& ctx); | ||
| 50 | void Handle_LoadLocationNameList(HLERequestContext& ctx); | ||
| 51 | void Handle_LoadTimeZoneRule(HLERequestContext& ctx); | ||
| 52 | void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx); | ||
| 53 | void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx); | ||
| 54 | void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx); | ||
| 55 | void Handle_ParseTimeZoneBinary(HLERequestContext& ctx); | ||
| 56 | void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx); | ||
| 57 | void Handle_ToCalendarTime(HLERequestContext& ctx); | ||
| 58 | void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx); | ||
| 59 | void Handle_ToPosixTime(HLERequestContext& ctx); | ||
| 60 | void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx); | ||
| 61 | |||
| 62 | Core::System& m_system; | ||
| 63 | |||
| 64 | StandardSteadyClockCore& m_clock_core; | ||
| 65 | TimeZone& m_time_zone; | ||
| 66 | bool m_can_write_timezone_device_location; | ||
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace Service::PSC::Time | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 39124c5fd..06cbad268 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -66,7 +66,6 @@ | |||
| 66 | #include "core/hle/service/sockets/sockets.h" | 66 | #include "core/hle/service/sockets/sockets.h" |
| 67 | #include "core/hle/service/spl/spl_module.h" | 67 | #include "core/hle/service/spl/spl_module.h" |
| 68 | #include "core/hle/service/ssl/ssl.h" | 68 | #include "core/hle/service/ssl/ssl.h" |
| 69 | #include "core/hle/service/time/time.h" | ||
| 70 | #include "core/hle/service/usb/usb.h" | 69 | #include "core/hle/service/usb/usb.h" |
| 71 | #include "core/hle/service/vi/vi.h" | 70 | #include "core/hle/service/vi/vi.h" |
| 72 | #include "core/reporter.h" | 71 | #include "core/reporter.h" |
| @@ -246,6 +245,9 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system | |||
| 246 | kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); }); | 245 | kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); }); |
| 247 | kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); }); | 246 | kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); }); |
| 248 | kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); }); | 247 | kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); }); |
| 248 | // glue depends on settings and psc, so they must come first | ||
| 249 | kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); | ||
| 250 | kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); | ||
| 249 | kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); }); | 251 | kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); }); |
| 250 | kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); }); | 252 | kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); }); |
| 251 | kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); }); | 253 | kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); }); |
| @@ -269,13 +271,10 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system | |||
| 269 | kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); }); | 271 | kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); }); |
| 270 | kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); }); | 272 | kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); }); |
| 271 | kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); | 273 | kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); |
| 272 | kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); | ||
| 273 | kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); | 274 | kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); |
| 274 | kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); | 275 | kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); |
| 275 | kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); | ||
| 276 | kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); | 276 | kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); |
| 277 | kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); | 277 | kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); |
| 278 | kernel.RunOnGuestCoreProcess("time", [&] { Time::LoopProcess(system); }); | ||
| 279 | kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); }); | 278 | kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); }); |
| 280 | // clang-format on | 279 | // clang-format on |
| 281 | } | 280 | } |
diff --git a/src/core/hle/service/set/private_settings.h b/src/core/hle/service/set/private_settings.h new file mode 100644 index 000000000..b02291ce7 --- /dev/null +++ b/src/core/hle/service/set/private_settings.h | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/uuid.h" | ||
| 12 | #include "core/hle/service/psc/time/common.h" | ||
| 13 | |||
| 14 | namespace Service::Set { | ||
| 15 | |||
| 16 | /// This is nn::settings::system::InitialLaunchFlag | ||
| 17 | struct InitialLaunchFlag { | ||
| 18 | union { | ||
| 19 | u32 raw{}; | ||
| 20 | |||
| 21 | BitField<0, 1, u32> InitialLaunchCompletionFlag; | ||
| 22 | BitField<8, 1, u32> InitialLaunchUserAdditionFlag; | ||
| 23 | BitField<16, 1, u32> InitialLaunchTimestampFlag; | ||
| 24 | }; | ||
| 25 | }; | ||
| 26 | static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size"); | ||
| 27 | |||
| 28 | /// This is nn::settings::system::InitialLaunchSettings | ||
| 29 | struct InitialLaunchSettings { | ||
| 30 | InitialLaunchFlag flags; | ||
| 31 | INSERT_PADDING_BYTES(0x4); | ||
| 32 | Service::PSC::Time::SteadyClockTimePoint timestamp; | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); | ||
| 35 | |||
| 36 | #pragma pack(push, 4) | ||
| 37 | struct InitialLaunchSettingsPacked { | ||
| 38 | InitialLaunchFlag flags; | ||
| 39 | Service::PSC::Time::SteadyClockTimePoint timestamp; | ||
| 40 | }; | ||
| 41 | #pragma pack(pop) | ||
| 42 | static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, | ||
| 43 | "InitialLaunchSettingsPacked is incorrect size"); | ||
| 44 | |||
| 45 | struct PrivateSettings { | ||
| 46 | std::array<u8, 0x10> reserved_00; | ||
| 47 | |||
| 48 | // nn::settings::system::InitialLaunchSettings | ||
| 49 | InitialLaunchSettings initial_launch_settings; | ||
| 50 | |||
| 51 | std::array<u8, 0x20> reserved_30; | ||
| 52 | |||
| 53 | Common::UUID external_clock_source_id; | ||
| 54 | s64 shutdown_rtc_value; | ||
| 55 | s64 external_steady_clock_internal_offset; | ||
| 56 | |||
| 57 | std::array<u8, 0x60> reserved_70; | ||
| 58 | |||
| 59 | // nn::settings::system::PlatformRegion | ||
| 60 | std::array<u8, 0x4> platform_region; | ||
| 61 | |||
| 62 | std::array<u8, 0x4> reserved_D4; | ||
| 63 | }; | ||
| 64 | static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10); | ||
| 65 | static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50); | ||
| 66 | static_assert(offsetof(PrivateSettings, reserved_70) == 0x70); | ||
| 67 | static_assert(offsetof(PrivateSettings, platform_region) == 0xD0); | ||
| 68 | static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!"); | ||
| 69 | |||
| 70 | PrivateSettings DefaultPrivateSettings(); | ||
| 71 | |||
| 72 | } // namespace Service::Set | ||
diff --git a/src/core/hle/service/set/setting_formats/private_settings.h b/src/core/hle/service/set/setting_formats/private_settings.h index 6c40f62e1..6579e95e0 100644 --- a/src/core/hle/service/set/setting_formats/private_settings.h +++ b/src/core/hle/service/set/setting_formats/private_settings.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/uuid.h" | 9 | #include "common/uuid.h" |
| 10 | #include "core/hle/service/set/settings_types.h" | 10 | #include "core/hle/service/set/settings_types.h" |
| 11 | #include "core/hle/service/time/clock_types.h" | ||
| 12 | 11 | ||
| 13 | namespace Service::Set { | 12 | namespace Service::Set { |
| 14 | 13 | ||
diff --git a/src/core/hle/service/set/setting_formats/system_settings.cpp b/src/core/hle/service/set/setting_formats/system_settings.cpp index 66e57651e..ec00b90a6 100644 --- a/src/core/hle/service/set/setting_formats/system_settings.cpp +++ b/src/core/hle/service/set/setting_formats/system_settings.cpp | |||
| @@ -45,7 +45,7 @@ SystemSettings DefaultSystemSettings() { | |||
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | settings.device_time_zone_location_name = {"UTC"}; | 47 | settings.device_time_zone_location_name = {"UTC"}; |
| 48 | settings.user_system_clock_automatic_correction_enabled = false; | 48 | settings.user_system_clock_automatic_correction_enabled = true; |
| 49 | 49 | ||
| 50 | settings.primary_album_storage = PrimaryAlbumStorage::SdCard; | 50 | settings.primary_album_storage = PrimaryAlbumStorage::SdCard; |
| 51 | settings.battery_percentage_flag = true; | 51 | settings.battery_percentage_flag = true; |
diff --git a/src/core/hle/service/set/setting_formats/system_settings.h b/src/core/hle/service/set/setting_formats/system_settings.h index 14654f8b1..af5929fa9 100644 --- a/src/core/hle/service/set/setting_formats/system_settings.h +++ b/src/core/hle/service/set/setting_formats/system_settings.h | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include "common/vector_math.h" | 12 | #include "common/vector_math.h" |
| 13 | #include "core/hle/service/set/setting_formats/private_settings.h" | 13 | #include "core/hle/service/set/setting_formats/private_settings.h" |
| 14 | #include "core/hle/service/set/settings_types.h" | 14 | #include "core/hle/service/set/settings_types.h" |
| 15 | #include "core/hle/service/time/clock_types.h" | ||
| 16 | 15 | ||
| 17 | namespace Service::Set { | 16 | namespace Service::Set { |
| 18 | 17 | ||
| @@ -197,12 +196,14 @@ struct SystemSettings { | |||
| 197 | std::array<u8, 0x2C> backlight_settings_mixed_up; | 196 | std::array<u8, 0x2C> backlight_settings_mixed_up; |
| 198 | INSERT_PADDING_BYTES(0x64); // Reserved | 197 | INSERT_PADDING_BYTES(0x64); // Reserved |
| 199 | 198 | ||
| 200 | Service::Time::Clock::SystemClockContext user_system_clock_context; | 199 | // nn::time::SystemClockContext |
| 201 | Service::Time::Clock::SystemClockContext network_system_clock_context; | 200 | Service::PSC::Time::SystemClockContext user_system_clock_context; |
| 201 | Service::PSC::Time::SystemClockContext network_system_clock_context; | ||
| 202 | bool user_system_clock_automatic_correction_enabled; | 202 | bool user_system_clock_automatic_correction_enabled; |
| 203 | INSERT_PADDING_BYTES(0x3); | 203 | INSERT_PADDING_BYTES(0x3); |
| 204 | INSERT_PADDING_BYTES(0x4); // Reserved | 204 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 205 | Service::Time::Clock::SteadyClockTimePoint | 205 | // nn::time::SteadyClockTimePoint |
| 206 | Service::PSC::Time::SteadyClockTimePoint | ||
| 206 | user_system_clock_automatic_correction_updated_time_point; | 207 | user_system_clock_automatic_correction_updated_time_point; |
| 207 | INSERT_PADDING_BYTES(0x10); // Reserved | 208 | INSERT_PADDING_BYTES(0x10); // Reserved |
| 208 | 209 | ||
| @@ -280,9 +281,12 @@ struct SystemSettings { | |||
| 280 | bool requires_run_repair_time_reviser; | 281 | bool requires_run_repair_time_reviser; |
| 281 | INSERT_PADDING_BYTES(0x6B); // Reserved | 282 | INSERT_PADDING_BYTES(0x6B); // Reserved |
| 282 | 283 | ||
| 283 | Service::Time::TimeZone::LocationName device_time_zone_location_name; | 284 | // nn::time::LocationName |
| 285 | Service::PSC::Time::LocationName device_time_zone_location_name; | ||
| 284 | INSERT_PADDING_BYTES(0x4); // Reserved | 286 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 285 | Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time; | 287 | // nn::time::SteadyClockTimePoint |
| 288 | Service::PSC::Time::SteadyClockTimePoint device_time_zone_location_updated_time; | ||
| 289 | |||
| 286 | INSERT_PADDING_BYTES(0xC0); // Reserved | 290 | INSERT_PADDING_BYTES(0xC0); // Reserved |
| 287 | 291 | ||
| 288 | // nn::settings::system::PrimaryAlbumStorage | 292 | // nn::settings::system::PrimaryAlbumStorage |
diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h index 4dee202d7..f6f227fde 100644 --- a/src/core/hle/service/set/settings_types.h +++ b/src/core/hle/service/set/settings_types.h | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/uuid.h" | 11 | #include "common/uuid.h" |
| 12 | #include "core/hle/service/time/clock_types.h" | 12 | #include "core/hle/service/psc/time/common.h" |
| 13 | 13 | ||
| 14 | namespace Service::Set { | 14 | namespace Service::Set { |
| 15 | 15 | ||
| @@ -365,7 +365,7 @@ struct EulaVersion { | |||
| 365 | EulaVersionClockType clock_type; | 365 | EulaVersionClockType clock_type; |
| 366 | INSERT_PADDING_BYTES(0x4); | 366 | INSERT_PADDING_BYTES(0x4); |
| 367 | s64 posix_time; | 367 | s64 posix_time; |
| 368 | Time::Clock::SteadyClockTimePoint timestamp; | 368 | Service::PSC::Time::SteadyClockTimePoint timestamp; |
| 369 | }; | 369 | }; |
| 370 | static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); | 370 | static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); |
| 371 | 371 | ||
| @@ -398,14 +398,14 @@ static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size" | |||
| 398 | struct InitialLaunchSettings { | 398 | struct InitialLaunchSettings { |
| 399 | InitialLaunchFlag flags; | 399 | InitialLaunchFlag flags; |
| 400 | INSERT_PADDING_BYTES(0x4); | 400 | INSERT_PADDING_BYTES(0x4); |
| 401 | Service::Time::Clock::SteadyClockTimePoint timestamp; | 401 | Service::PSC::Time::SteadyClockTimePoint timestamp; |
| 402 | }; | 402 | }; |
| 403 | static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); | 403 | static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); |
| 404 | 404 | ||
| 405 | #pragma pack(push, 4) | 405 | #pragma pack(push, 4) |
| 406 | struct InitialLaunchSettingsPacked { | 406 | struct InitialLaunchSettingsPacked { |
| 407 | InitialLaunchFlag flags; | 407 | InitialLaunchFlag flags; |
| 408 | Service::Time::Clock::SteadyClockTimePoint timestamp; | 408 | Service::PSC::Time::SteadyClockTimePoint timestamp; |
| 409 | }; | 409 | }; |
| 410 | #pragma pack(pop) | 410 | #pragma pack(pop) |
| 411 | static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, | 411 | static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, |
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index 429e96d11..f40a1c8f3 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp | |||
| @@ -489,11 +489,10 @@ void ISystemSettingsServer::SetExternalSteadyClockSourceId(HLERequestContext& ct | |||
| 489 | void ISystemSettingsServer::GetUserSystemClockContext(HLERequestContext& ctx) { | 489 | void ISystemSettingsServer::GetUserSystemClockContext(HLERequestContext& ctx) { |
| 490 | LOG_INFO(Service_SET, "called"); | 490 | LOG_INFO(Service_SET, "called"); |
| 491 | 491 | ||
| 492 | Service::Time::Clock::SystemClockContext context{}; | 492 | Service::PSC::Time::SystemClockContext context{}; |
| 493 | auto res = GetUserSystemClockContext(context); | 493 | auto res = GetUserSystemClockContext(context); |
| 494 | 494 | ||
| 495 | IPC::ResponseBuilder rb{ctx, | 495 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::SystemClockContext) / sizeof(u32)}; |
| 496 | 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)}; | ||
| 497 | rb.Push(res); | 496 | rb.Push(res); |
| 498 | rb.PushRaw(context); | 497 | rb.PushRaw(context); |
| 499 | } | 498 | } |
| @@ -502,7 +501,7 @@ void ISystemSettingsServer::SetUserSystemClockContext(HLERequestContext& ctx) { | |||
| 502 | LOG_INFO(Service_SET, "called"); | 501 | LOG_INFO(Service_SET, "called"); |
| 503 | 502 | ||
| 504 | IPC::RequestParser rp{ctx}; | 503 | IPC::RequestParser rp{ctx}; |
| 505 | auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; | 504 | auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; |
| 506 | 505 | ||
| 507 | auto res = SetUserSystemClockContext(context); | 506 | auto res = SetUserSystemClockContext(context); |
| 508 | 507 | ||
| @@ -809,19 +808,19 @@ void ISystemSettingsServer::GetQuestFlag(HLERequestContext& ctx) { | |||
| 809 | void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { | 808 | void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { |
| 810 | LOG_INFO(Service_SET, "called"); | 809 | LOG_INFO(Service_SET, "called"); |
| 811 | 810 | ||
| 812 | Service::Time::TimeZone::LocationName name{}; | 811 | Service::PSC::Time::LocationName name{}; |
| 813 | auto res = GetDeviceTimeZoneLocationName(name); | 812 | auto res = GetDeviceTimeZoneLocationName(name); |
| 814 | 813 | ||
| 815 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::Time::TimeZone::LocationName) / sizeof(u32)}; | 814 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)}; |
| 816 | rb.Push(res); | 815 | rb.Push(res); |
| 817 | rb.PushRaw<Service::Time::TimeZone::LocationName>(name); | 816 | rb.PushRaw<Service::PSC::Time::LocationName>(name); |
| 818 | } | 817 | } |
| 819 | 818 | ||
| 820 | void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { | 819 | void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { |
| 821 | LOG_INFO(Service_SET, "called"); | 820 | LOG_INFO(Service_SET, "called"); |
| 822 | 821 | ||
| 823 | IPC::RequestParser rp{ctx}; | 822 | IPC::RequestParser rp{ctx}; |
| 824 | auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()}; | 823 | auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; |
| 825 | 824 | ||
| 826 | auto res = SetDeviceTimeZoneLocationName(name); | 825 | auto res = SetDeviceTimeZoneLocationName(name); |
| 827 | 826 | ||
| @@ -843,11 +842,10 @@ void ISystemSettingsServer::SetRegionCode(HLERequestContext& ctx) { | |||
| 843 | void ISystemSettingsServer::GetNetworkSystemClockContext(HLERequestContext& ctx) { | 842 | void ISystemSettingsServer::GetNetworkSystemClockContext(HLERequestContext& ctx) { |
| 844 | LOG_INFO(Service_SET, "called"); | 843 | LOG_INFO(Service_SET, "called"); |
| 845 | 844 | ||
| 846 | Service::Time::Clock::SystemClockContext context{}; | 845 | Service::PSC::Time::SystemClockContext context{}; |
| 847 | auto res = GetNetworkSystemClockContext(context); | 846 | auto res = GetNetworkSystemClockContext(context); |
| 848 | 847 | ||
| 849 | IPC::ResponseBuilder rb{ctx, | 848 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::SystemClockContext) / sizeof(u32)}; |
| 850 | 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)}; | ||
| 851 | rb.Push(res); | 849 | rb.Push(res); |
| 852 | rb.PushRaw(context); | 850 | rb.PushRaw(context); |
| 853 | } | 851 | } |
| @@ -856,7 +854,7 @@ void ISystemSettingsServer::SetNetworkSystemClockContext(HLERequestContext& ctx) | |||
| 856 | LOG_INFO(Service_SET, "called"); | 854 | LOG_INFO(Service_SET, "called"); |
| 857 | 855 | ||
| 858 | IPC::RequestParser rp{ctx}; | 856 | IPC::RequestParser rp{ctx}; |
| 859 | auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; | 857 | auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; |
| 860 | 858 | ||
| 861 | auto res = SetNetworkSystemClockContext(context); | 859 | auto res = SetNetworkSystemClockContext(context); |
| 862 | 860 | ||
| @@ -1141,19 +1139,19 @@ void ISystemSettingsServer::GetKeyboardLayout(HLERequestContext& ctx) { | |||
| 1141 | void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { | 1139 | void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { |
| 1142 | LOG_INFO(Service_SET, "called"); | 1140 | LOG_INFO(Service_SET, "called"); |
| 1143 | 1141 | ||
| 1144 | Service::Time::Clock::SteadyClockTimePoint time_point{}; | 1142 | Service::PSC::Time::SteadyClockTimePoint time_point{}; |
| 1145 | auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); | 1143 | auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); |
| 1146 | 1144 | ||
| 1147 | IPC::ResponseBuilder rb{ctx, 4}; | 1145 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1148 | rb.Push(res); | 1146 | rb.Push(res); |
| 1149 | rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); | 1147 | rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); |
| 1150 | } | 1148 | } |
| 1151 | 1149 | ||
| 1152 | void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { | 1150 | void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { |
| 1153 | LOG_INFO(Service_SET, "called"); | 1151 | LOG_INFO(Service_SET, "called"); |
| 1154 | 1152 | ||
| 1155 | IPC::RequestParser rp{ctx}; | 1153 | IPC::RequestParser rp{ctx}; |
| 1156 | auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; | 1154 | auto time_point{rp.PopRaw<Service::PSC::Time::SteadyClockTimePoint>()}; |
| 1157 | 1155 | ||
| 1158 | auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point); | 1156 | auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point); |
| 1159 | 1157 | ||
| @@ -1165,12 +1163,12 @@ void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( | |||
| 1165 | HLERequestContext& ctx) { | 1163 | HLERequestContext& ctx) { |
| 1166 | LOG_INFO(Service_SET, "called"); | 1164 | LOG_INFO(Service_SET, "called"); |
| 1167 | 1165 | ||
| 1168 | Service::Time::Clock::SteadyClockTimePoint time_point{}; | 1166 | Service::PSC::Time::SteadyClockTimePoint time_point{}; |
| 1169 | auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | 1167 | auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); |
| 1170 | 1168 | ||
| 1171 | IPC::ResponseBuilder rb{ctx, 4}; | 1169 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1172 | rb.Push(res); | 1170 | rb.Push(res); |
| 1173 | rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); | 1171 | rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); |
| 1174 | } | 1172 | } |
| 1175 | 1173 | ||
| 1176 | void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( | 1174 | void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( |
| @@ -1178,7 +1176,7 @@ void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( | |||
| 1178 | LOG_INFO(Service_SET, "called"); | 1176 | LOG_INFO(Service_SET, "called"); |
| 1179 | 1177 | ||
| 1180 | IPC::RequestParser rp{ctx}; | 1178 | IPC::RequestParser rp{ctx}; |
| 1181 | auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; | 1179 | auto time_point{rp.PopRaw<Service::PSC::Time::SteadyClockTimePoint>()}; |
| 1182 | 1180 | ||
| 1183 | auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | 1181 | auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); |
| 1184 | 1182 | ||
| @@ -1257,25 +1255,25 @@ void ISystemSettingsServer::StoreSettings() { | |||
| 1257 | auto system_dir = | 1255 | auto system_dir = |
| 1258 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; | 1256 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; |
| 1259 | if (!StoreSettingsFile(system_dir, m_system_settings)) { | 1257 | if (!StoreSettingsFile(system_dir, m_system_settings)) { |
| 1260 | LOG_ERROR(HW_GPU, "Failed to store System settings"); | 1258 | LOG_ERROR(Service_SET, "Failed to store System settings"); |
| 1261 | } | 1259 | } |
| 1262 | 1260 | ||
| 1263 | auto private_dir = | 1261 | auto private_dir = |
| 1264 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; | 1262 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; |
| 1265 | if (!StoreSettingsFile(private_dir, m_private_settings)) { | 1263 | if (!StoreSettingsFile(private_dir, m_private_settings)) { |
| 1266 | LOG_ERROR(HW_GPU, "Failed to store Private settings"); | 1264 | LOG_ERROR(Service_SET, "Failed to store Private settings"); |
| 1267 | } | 1265 | } |
| 1268 | 1266 | ||
| 1269 | auto device_dir = | 1267 | auto device_dir = |
| 1270 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; | 1268 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; |
| 1271 | if (!StoreSettingsFile(device_dir, m_device_settings)) { | 1269 | if (!StoreSettingsFile(device_dir, m_device_settings)) { |
| 1272 | LOG_ERROR(HW_GPU, "Failed to store Device settings"); | 1270 | LOG_ERROR(Service_SET, "Failed to store Device settings"); |
| 1273 | } | 1271 | } |
| 1274 | 1272 | ||
| 1275 | auto appln_dir = | 1273 | auto appln_dir = |
| 1276 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; | 1274 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; |
| 1277 | if (!StoreSettingsFile(appln_dir, m_appln_settings)) { | 1275 | if (!StoreSettingsFile(appln_dir, m_appln_settings)) { |
| 1278 | LOG_ERROR(HW_GPU, "Failed to store ApplLn settings"); | 1276 | LOG_ERROR(Service_SET, "Failed to store ApplLn settings"); |
| 1279 | } | 1277 | } |
| 1280 | } | 1278 | } |
| 1281 | 1279 | ||
| @@ -1318,39 +1316,39 @@ Result ISystemSettingsServer::SetExternalSteadyClockSourceId(Common::UUID id) { | |||
| 1318 | } | 1316 | } |
| 1319 | 1317 | ||
| 1320 | Result ISystemSettingsServer::GetUserSystemClockContext( | 1318 | Result ISystemSettingsServer::GetUserSystemClockContext( |
| 1321 | Service::Time::Clock::SystemClockContext& out_context) { | 1319 | Service::PSC::Time::SystemClockContext& out_context) { |
| 1322 | out_context = m_system_settings.user_system_clock_context; | 1320 | out_context = m_system_settings.user_system_clock_context; |
| 1323 | R_SUCCEED(); | 1321 | R_SUCCEED(); |
| 1324 | } | 1322 | } |
| 1325 | 1323 | ||
| 1326 | Result ISystemSettingsServer::SetUserSystemClockContext( | 1324 | Result ISystemSettingsServer::SetUserSystemClockContext( |
| 1327 | Service::Time::Clock::SystemClockContext& context) { | 1325 | Service::PSC::Time::SystemClockContext& context) { |
| 1328 | m_system_settings.user_system_clock_context = context; | 1326 | m_system_settings.user_system_clock_context = context; |
| 1329 | SetSaveNeeded(); | 1327 | SetSaveNeeded(); |
| 1330 | R_SUCCEED(); | 1328 | R_SUCCEED(); |
| 1331 | } | 1329 | } |
| 1332 | 1330 | ||
| 1333 | Result ISystemSettingsServer::GetDeviceTimeZoneLocationName( | 1331 | Result ISystemSettingsServer::GetDeviceTimeZoneLocationName( |
| 1334 | Service::Time::TimeZone::LocationName& out_name) { | 1332 | Service::PSC::Time::LocationName& out_name) { |
| 1335 | out_name = m_system_settings.device_time_zone_location_name; | 1333 | out_name = m_system_settings.device_time_zone_location_name; |
| 1336 | R_SUCCEED(); | 1334 | R_SUCCEED(); |
| 1337 | } | 1335 | } |
| 1338 | 1336 | ||
| 1339 | Result ISystemSettingsServer::SetDeviceTimeZoneLocationName( | 1337 | Result ISystemSettingsServer::SetDeviceTimeZoneLocationName( |
| 1340 | Service::Time::TimeZone::LocationName& name) { | 1338 | Service::PSC::Time::LocationName& name) { |
| 1341 | m_system_settings.device_time_zone_location_name = name; | 1339 | m_system_settings.device_time_zone_location_name = name; |
| 1342 | SetSaveNeeded(); | 1340 | SetSaveNeeded(); |
| 1343 | R_SUCCEED(); | 1341 | R_SUCCEED(); |
| 1344 | } | 1342 | } |
| 1345 | 1343 | ||
| 1346 | Result ISystemSettingsServer::GetNetworkSystemClockContext( | 1344 | Result ISystemSettingsServer::GetNetworkSystemClockContext( |
| 1347 | Service::Time::Clock::SystemClockContext& out_context) { | 1345 | Service::PSC::Time::SystemClockContext& out_context) { |
| 1348 | out_context = m_system_settings.network_system_clock_context; | 1346 | out_context = m_system_settings.network_system_clock_context; |
| 1349 | R_SUCCEED(); | 1347 | R_SUCCEED(); |
| 1350 | } | 1348 | } |
| 1351 | 1349 | ||
| 1352 | Result ISystemSettingsServer::SetNetworkSystemClockContext( | 1350 | Result ISystemSettingsServer::SetNetworkSystemClockContext( |
| 1353 | Service::Time::Clock::SystemClockContext& context) { | 1351 | Service::PSC::Time::SystemClockContext& context) { |
| 1354 | m_system_settings.network_system_clock_context = context; | 1352 | m_system_settings.network_system_clock_context = context; |
| 1355 | SetSaveNeeded(); | 1353 | SetSaveNeeded(); |
| 1356 | R_SUCCEED(); | 1354 | R_SUCCEED(); |
| @@ -1379,26 +1377,26 @@ Result ISystemSettingsServer::GetExternalSteadyClockInternalOffset(s64& out_offs | |||
| 1379 | } | 1377 | } |
| 1380 | 1378 | ||
| 1381 | Result ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime( | 1379 | Result ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime( |
| 1382 | Service::Time::Clock::SteadyClockTimePoint& out_time_point) { | 1380 | Service::PSC::Time::SteadyClockTimePoint& out_time_point) { |
| 1383 | out_time_point = m_system_settings.device_time_zone_location_updated_time; | 1381 | out_time_point = m_system_settings.device_time_zone_location_updated_time; |
| 1384 | R_SUCCEED(); | 1382 | R_SUCCEED(); |
| 1385 | } | 1383 | } |
| 1386 | 1384 | ||
| 1387 | Result ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime( | 1385 | Result ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime( |
| 1388 | Service::Time::Clock::SteadyClockTimePoint& time_point) { | 1386 | Service::PSC::Time::SteadyClockTimePoint& time_point) { |
| 1389 | m_system_settings.device_time_zone_location_updated_time = time_point; | 1387 | m_system_settings.device_time_zone_location_updated_time = time_point; |
| 1390 | SetSaveNeeded(); | 1388 | SetSaveNeeded(); |
| 1391 | R_SUCCEED(); | 1389 | R_SUCCEED(); |
| 1392 | } | 1390 | } |
| 1393 | 1391 | ||
| 1394 | Result ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( | 1392 | Result ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( |
| 1395 | Service::Time::Clock::SteadyClockTimePoint& out_time_point) { | 1393 | Service::PSC::Time::SteadyClockTimePoint& out_time_point) { |
| 1396 | out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point; | 1394 | out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point; |
| 1397 | R_SUCCEED(); | 1395 | R_SUCCEED(); |
| 1398 | } | 1396 | } |
| 1399 | 1397 | ||
| 1400 | Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( | 1398 | Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( |
| 1401 | Service::Time::Clock::SteadyClockTimePoint out_time_point) { | 1399 | Service::PSC::Time::SteadyClockTimePoint out_time_point) { |
| 1402 | m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point; | 1400 | m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point; |
| 1403 | SetSaveNeeded(); | 1401 | SetSaveNeeded(); |
| 1404 | R_SUCCEED(); | 1402 | R_SUCCEED(); |
diff --git a/src/core/hle/service/set/system_settings_server.h b/src/core/hle/service/set/system_settings_server.h index 32716f567..a2258d16d 100644 --- a/src/core/hle/service/set/system_settings_server.h +++ b/src/core/hle/service/set/system_settings_server.h | |||
| @@ -11,14 +11,13 @@ | |||
| 11 | #include "common/polyfill_thread.h" | 11 | #include "common/polyfill_thread.h" |
| 12 | #include "common/uuid.h" | 12 | #include "common/uuid.h" |
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | #include "core/hle/service/psc/time/common.h" | ||
| 14 | #include "core/hle/service/service.h" | 15 | #include "core/hle/service/service.h" |
| 15 | #include "core/hle/service/set/setting_formats/appln_settings.h" | 16 | #include "core/hle/service/set/setting_formats/appln_settings.h" |
| 16 | #include "core/hle/service/set/setting_formats/device_settings.h" | 17 | #include "core/hle/service/set/setting_formats/device_settings.h" |
| 17 | #include "core/hle/service/set/setting_formats/private_settings.h" | 18 | #include "core/hle/service/set/setting_formats/private_settings.h" |
| 18 | #include "core/hle/service/set/setting_formats/system_settings.h" | 19 | #include "core/hle/service/set/setting_formats/system_settings.h" |
| 19 | #include "core/hle/service/set/settings_types.h" | 20 | #include "core/hle/service/set/settings_types.h" |
| 20 | #include "core/hle/service/time/clock_types.h" | ||
| 21 | #include "core/hle/service/time/time_zone_types.h" | ||
| 22 | 21 | ||
| 23 | namespace Core { | 22 | namespace Core { |
| 24 | class System; | 23 | class System; |
| @@ -51,24 +50,24 @@ public: | |||
| 51 | 50 | ||
| 52 | Result GetExternalSteadyClockSourceId(Common::UUID& out_id); | 51 | Result GetExternalSteadyClockSourceId(Common::UUID& out_id); |
| 53 | Result SetExternalSteadyClockSourceId(Common::UUID id); | 52 | Result SetExternalSteadyClockSourceId(Common::UUID id); |
| 54 | Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); | 53 | Result GetUserSystemClockContext(Service::PSC::Time::SystemClockContext& out_context); |
| 55 | Result SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context); | 54 | Result SetUserSystemClockContext(Service::PSC::Time::SystemClockContext& context); |
| 56 | Result GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name); | 55 | Result GetDeviceTimeZoneLocationName(Service::PSC::Time::LocationName& out_name); |
| 57 | Result SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name); | 56 | Result SetDeviceTimeZoneLocationName(Service::PSC::Time::LocationName& name); |
| 58 | Result GetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); | 57 | Result GetNetworkSystemClockContext(Service::PSC::Time::SystemClockContext& out_context); |
| 59 | Result SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context); | 58 | Result SetNetworkSystemClockContext(Service::PSC::Time::SystemClockContext& context); |
| 60 | Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled); | 59 | Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled); |
| 61 | Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled); | 60 | Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled); |
| 62 | Result SetExternalSteadyClockInternalOffset(s64 offset); | 61 | Result SetExternalSteadyClockInternalOffset(s64 offset); |
| 63 | Result GetExternalSteadyClockInternalOffset(s64& out_offset); | 62 | Result GetExternalSteadyClockInternalOffset(s64& out_offset); |
| 64 | Result GetDeviceTimeZoneLocationUpdatedTime( | 63 | Result GetDeviceTimeZoneLocationUpdatedTime( |
| 65 | Service::Time::Clock::SteadyClockTimePoint& out_time_point); | 64 | Service::PSC::Time::SteadyClockTimePoint& out_time_point); |
| 66 | Result SetDeviceTimeZoneLocationUpdatedTime( | 65 | Result SetDeviceTimeZoneLocationUpdatedTime( |
| 67 | Service::Time::Clock::SteadyClockTimePoint& time_point); | 66 | Service::PSC::Time::SteadyClockTimePoint& time_point); |
| 68 | Result GetUserSystemClockAutomaticCorrectionUpdatedTime( | 67 | Result GetUserSystemClockAutomaticCorrectionUpdatedTime( |
| 69 | Service::Time::Clock::SteadyClockTimePoint& out_time_point); | 68 | Service::PSC::Time::SteadyClockTimePoint& out_time_point); |
| 70 | Result SetUserSystemClockAutomaticCorrectionUpdatedTime( | 69 | Result SetUserSystemClockAutomaticCorrectionUpdatedTime( |
| 71 | Service::Time::Clock::SteadyClockTimePoint time_point); | 70 | Service::PSC::Time::SteadyClockTimePoint time_point); |
| 72 | 71 | ||
| 73 | private: | 72 | private: |
| 74 | void SetLanguageCode(HLERequestContext& ctx); | 73 | void SetLanguageCode(HLERequestContext& ctx); |
| @@ -147,8 +146,8 @@ private: | |||
| 147 | PrivateSettings m_private_settings{}; | 146 | PrivateSettings m_private_settings{}; |
| 148 | DeviceSettings m_device_settings{}; | 147 | DeviceSettings m_device_settings{}; |
| 149 | ApplnSettings m_appln_settings{}; | 148 | ApplnSettings m_appln_settings{}; |
| 150 | std::jthread m_save_thread; | ||
| 151 | std::mutex m_save_needed_mutex; | 149 | std::mutex m_save_needed_mutex; |
| 150 | std::jthread m_save_thread; | ||
| 152 | bool m_save_needed{false}; | 151 | bool m_save_needed{false}; |
| 153 | }; | 152 | }; |
| 154 | 153 | ||
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 4ae32a9c1..32c218638 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <chrono> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <mutex> | 8 | #include <mutex> |
| 8 | #include <string> | 9 | #include <string> |
| @@ -10,6 +11,7 @@ | |||
| 10 | 11 | ||
| 11 | #include "common/concepts.h" | 12 | #include "common/concepts.h" |
| 12 | #include "core/hle/kernel/k_port.h" | 13 | #include "core/hle/kernel/k_port.h" |
| 14 | #include "core/hle/kernel/svc.h" | ||
| 13 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 14 | #include "core/hle/service/service.h" | 16 | #include "core/hle/service/service.h" |
| 15 | 17 | ||
| @@ -62,12 +64,21 @@ public: | |||
| 62 | Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name); | 64 | Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name); |
| 63 | 65 | ||
| 64 | template <Common::DerivedFrom<SessionRequestHandler> T> | 66 | template <Common::DerivedFrom<SessionRequestHandler> T> |
| 65 | std::shared_ptr<T> GetService(const std::string& service_name) const { | 67 | std::shared_ptr<T> GetService(const std::string& service_name, bool block = false) const { |
| 66 | auto service = registered_services.find(service_name); | 68 | auto service = registered_services.find(service_name); |
| 67 | if (service == registered_services.end()) { | 69 | if (service == registered_services.end() && !block) { |
| 68 | LOG_DEBUG(Service, "Can't find service: {}", service_name); | 70 | LOG_DEBUG(Service, "Can't find service: {}", service_name); |
| 69 | return nullptr; | 71 | return nullptr; |
| 72 | } else if (block) { | ||
| 73 | using namespace std::literals::chrono_literals; | ||
| 74 | while (service == registered_services.end()) { | ||
| 75 | Kernel::Svc::SleepThread( | ||
| 76 | kernel.System(), | ||
| 77 | std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count()); | ||
| 78 | service = registered_services.find(service_name); | ||
| 79 | } | ||
| 70 | } | 80 | } |
| 81 | |||
| 71 | return std::static_pointer_cast<T>(service->second()); | 82 | return std::static_pointer_cast<T>(service->second()); |
| 72 | } | 83 | } |
| 73 | 84 | ||
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h deleted file mode 100644 index 7149fffeb..000000000 --- a/src/core/hle/service/time/clock_types.h +++ /dev/null | |||
| @@ -1,129 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <ratio> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/uuid.h" | ||
| 11 | #include "core/hle/service/time/errors.h" | ||
| 12 | #include "core/hle/service/time/time_zone_types.h" | ||
| 13 | |||
| 14 | // Defined by WinBase.h on Windows | ||
| 15 | #ifdef GetCurrentTime | ||
| 16 | #undef GetCurrentTime | ||
| 17 | #endif | ||
| 18 | |||
| 19 | namespace Service::Time::Clock { | ||
| 20 | |||
| 21 | enum class TimeType : u8 { | ||
| 22 | UserSystemClock, | ||
| 23 | NetworkSystemClock, | ||
| 24 | LocalSystemClock, | ||
| 25 | }; | ||
| 26 | |||
| 27 | /// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint | ||
| 28 | struct SteadyClockTimePoint { | ||
| 29 | s64 time_point; | ||
| 30 | Common::UUID clock_source_id; | ||
| 31 | |||
| 32 | Result GetSpanBetween(SteadyClockTimePoint other, s64& span) const { | ||
| 33 | span = 0; | ||
| 34 | |||
| 35 | if (clock_source_id != other.clock_source_id) { | ||
| 36 | return ERROR_TIME_MISMATCH; | ||
| 37 | } | ||
| 38 | |||
| 39 | span = other.time_point - time_point; | ||
| 40 | |||
| 41 | return ResultSuccess; | ||
| 42 | } | ||
| 43 | |||
| 44 | static SteadyClockTimePoint GetRandom() { | ||
| 45 | return {0, Common::UUID::MakeRandom()}; | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); | ||
| 49 | static_assert(std::is_trivially_copyable_v<SteadyClockTimePoint>, | ||
| 50 | "SteadyClockTimePoint must be trivially copyable"); | ||
| 51 | |||
| 52 | struct SteadyClockContext { | ||
| 53 | u64 internal_offset; | ||
| 54 | Common::UUID steady_time_point; | ||
| 55 | }; | ||
| 56 | static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size"); | ||
| 57 | static_assert(std::is_trivially_copyable_v<SteadyClockContext>, | ||
| 58 | "SteadyClockContext must be trivially copyable"); | ||
| 59 | using StandardSteadyClockTimePointType = SteadyClockContext; | ||
| 60 | |||
| 61 | struct SystemClockContext { | ||
| 62 | s64 offset; | ||
| 63 | SteadyClockTimePoint steady_time_point; | ||
| 64 | }; | ||
| 65 | static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorrect size"); | ||
| 66 | static_assert(std::is_trivially_copyable_v<SystemClockContext>, | ||
| 67 | "SystemClockContext must be trivially copyable"); | ||
| 68 | |||
| 69 | struct ContinuousAdjustmentTimePoint { | ||
| 70 | s64 measurement_offset; | ||
| 71 | s64 diff_scale; | ||
| 72 | u32 shift_amount; | ||
| 73 | s64 lower; | ||
| 74 | s64 upper; | ||
| 75 | Common::UUID clock_source_id; | ||
| 76 | }; | ||
| 77 | static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38); | ||
| 78 | static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>, | ||
| 79 | "ContinuousAdjustmentTimePoint must be trivially copyable"); | ||
| 80 | |||
| 81 | /// https://switchbrew.org/wiki/Glue_services#TimeSpanType | ||
| 82 | struct TimeSpanType { | ||
| 83 | s64 nanoseconds{}; | ||
| 84 | |||
| 85 | s64 ToSeconds() const { | ||
| 86 | return nanoseconds / std::nano::den; | ||
| 87 | } | ||
| 88 | |||
| 89 | static TimeSpanType FromSeconds(s64 seconds) { | ||
| 90 | return {seconds * std::nano::den}; | ||
| 91 | } | ||
| 92 | |||
| 93 | template <u64 Frequency> | ||
| 94 | static TimeSpanType FromTicks(u64 ticks) { | ||
| 95 | using TicksToNSRatio = std::ratio<std::nano::den, Frequency>; | ||
| 96 | return {static_cast<s64>(ticks * TicksToNSRatio::num / TicksToNSRatio::den)}; | ||
| 97 | } | ||
| 98 | }; | ||
| 99 | static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); | ||
| 100 | |||
| 101 | struct ClockSnapshot { | ||
| 102 | SystemClockContext user_context; | ||
| 103 | SystemClockContext network_context; | ||
| 104 | s64 user_time; | ||
| 105 | s64 network_time; | ||
| 106 | TimeZone::CalendarTime user_calendar_time; | ||
| 107 | TimeZone::CalendarTime network_calendar_time; | ||
| 108 | TimeZone::CalendarAdditionalInfo user_calendar_additional_time; | ||
| 109 | TimeZone::CalendarAdditionalInfo network_calendar_additional_time; | ||
| 110 | SteadyClockTimePoint steady_clock_time_point; | ||
| 111 | TimeZone::LocationName location_name; | ||
| 112 | u8 is_automatic_correction_enabled; | ||
| 113 | TimeType type; | ||
| 114 | INSERT_PADDING_BYTES_NOINIT(0x2); | ||
| 115 | |||
| 116 | static Result GetCurrentTime(s64& current_time, | ||
| 117 | const SteadyClockTimePoint& steady_clock_time_point, | ||
| 118 | const SystemClockContext& context) { | ||
| 119 | if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) { | ||
| 120 | current_time = 0; | ||
| 121 | return ERROR_TIME_MISMATCH; | ||
| 122 | } | ||
| 123 | current_time = steady_clock_time_point.time_point + context.offset; | ||
| 124 | return ResultSuccess; | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size"); | ||
| 128 | |||
| 129 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h deleted file mode 100644 index 0f928a5a5..000000000 --- a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 7 | |||
| 8 | namespace Service::Time::Clock { | ||
| 9 | |||
| 10 | class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { | ||
| 11 | public: | ||
| 12 | EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {} | ||
| 13 | }; | ||
| 14 | |||
| 15 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_core.h b/src/core/hle/service/time/ephemeral_network_system_clock_core.h deleted file mode 100644 index 0a5f5aafb..000000000 --- a/src/core/hle/service/time/ephemeral_network_system_clock_core.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/system_clock_core.h" | ||
| 7 | |||
| 8 | namespace Service::Time::Clock { | ||
| 9 | |||
| 10 | class EphemeralNetworkSystemClockCore final : public SystemClockCore { | ||
| 11 | public: | ||
| 12 | explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_) | ||
| 13 | : SystemClockCore{steady_clock_core_} {} | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/errors.h b/src/core/hle/service/time/errors.h deleted file mode 100644 index 6655d30e1..000000000 --- a/src/core/hle/service/time/errors.h +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | |||
| 8 | namespace Service::Time { | ||
| 9 | |||
| 10 | constexpr Result ERROR_PERMISSION_DENIED{ErrorModule::Time, 1}; | ||
| 11 | constexpr Result ERROR_TIME_MISMATCH{ErrorModule::Time, 102}; | ||
| 12 | constexpr Result ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103}; | ||
| 13 | constexpr Result ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200}; | ||
| 14 | constexpr Result ERROR_OVERFLOW{ErrorModule::Time, 201}; | ||
| 15 | constexpr Result ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801}; | ||
| 16 | constexpr Result ERROR_OUT_OF_RANGE{ErrorModule::Time, 902}; | ||
| 17 | constexpr Result ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903}; | ||
| 18 | constexpr Result ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989}; | ||
| 19 | constexpr Result ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990}; | ||
| 20 | |||
| 21 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/local_system_clock_context_writer.h b/src/core/hle/service/time/local_system_clock_context_writer.h deleted file mode 100644 index 1639ef2b9..000000000 --- a/src/core/hle/service/time/local_system_clock_context_writer.h +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 7 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback { | ||
| 12 | public: | ||
| 13 | explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_) | ||
| 14 | : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {} | ||
| 15 | |||
| 16 | protected: | ||
| 17 | Result Update() override { | ||
| 18 | shared_memory.UpdateLocalSystemClockContext(context); | ||
| 19 | return ResultSuccess; | ||
| 20 | } | ||
| 21 | |||
| 22 | private: | ||
| 23 | SharedMemory& shared_memory; | ||
| 24 | }; | ||
| 25 | |||
| 26 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/network_system_clock_context_writer.h b/src/core/hle/service/time/network_system_clock_context_writer.h deleted file mode 100644 index 655e4c06d..000000000 --- a/src/core/hle/service/time/network_system_clock_context_writer.h +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/errors.h" | ||
| 7 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 8 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 9 | |||
| 10 | namespace Service::Time::Clock { | ||
| 11 | |||
| 12 | class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { | ||
| 13 | public: | ||
| 14 | explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_) | ||
| 15 | : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {} | ||
| 16 | |||
| 17 | protected: | ||
| 18 | Result Update() override { | ||
| 19 | shared_memory.UpdateNetworkSystemClockContext(context); | ||
| 20 | return ResultSuccess; | ||
| 21 | } | ||
| 22 | |||
| 23 | private: | ||
| 24 | SharedMemory& shared_memory; | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_local_system_clock_core.h b/src/core/hle/service/time/standard_local_system_clock_core.h deleted file mode 100644 index ae2ff1bfd..000000000 --- a/src/core/hle/service/time/standard_local_system_clock_core.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/system_clock_core.h" | ||
| 7 | |||
| 8 | namespace Service::Time::Clock { | ||
| 9 | |||
| 10 | class StandardLocalSystemClockCore final : public SystemClockCore { | ||
| 11 | public: | ||
| 12 | explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_) | ||
| 13 | : SystemClockCore{steady_clock_core_} {} | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_network_system_clock_core.h b/src/core/hle/service/time/standard_network_system_clock_core.h deleted file mode 100644 index c1ec5252b..000000000 --- a/src/core/hle/service/time/standard_network_system_clock_core.h +++ /dev/null | |||
| @@ -1,45 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/clock_types.h" | ||
| 7 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 8 | #include "core/hle/service/time/system_clock_core.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Time::Clock { | ||
| 15 | |||
| 16 | class StandardNetworkSystemClockCore final : public SystemClockCore { | ||
| 17 | public: | ||
| 18 | explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_) | ||
| 19 | : SystemClockCore{steady_clock_core_} {} | ||
| 20 | |||
| 21 | void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) { | ||
| 22 | standard_network_clock_sufficient_accuracy = value; | ||
| 23 | } | ||
| 24 | |||
| 25 | bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const { | ||
| 26 | SystemClockContext clock_ctx{}; | ||
| 27 | if (GetClockContext(system, clock_ctx) != ResultSuccess) { | ||
| 28 | return {}; | ||
| 29 | } | ||
| 30 | |||
| 31 | s64 span{}; | ||
| 32 | if (clock_ctx.steady_time_point.GetSpanBetween( | ||
| 33 | GetSteadyClockCore().GetCurrentTimePoint(system), span) != ResultSuccess) { | ||
| 34 | return {}; | ||
| 35 | } | ||
| 36 | |||
| 37 | return TimeSpanType{span}.nanoseconds < | ||
| 38 | standard_network_clock_sufficient_accuracy.nanoseconds; | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | TimeSpanType standard_network_clock_sufficient_accuracy{}; | ||
| 43 | }; | ||
| 44 | |||
| 45 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp deleted file mode 100644 index 5627b7003..000000000 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hardware_properties.h" | ||
| 7 | #include "core/hle/service/time/standard_steady_clock_core.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { | ||
| 12 | const TimeSpanType ticks_time_span{ | ||
| 13 | TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())}; | ||
| 14 | TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; | ||
| 15 | |||
| 16 | if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { | ||
| 17 | raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds; | ||
| 18 | } | ||
| 19 | |||
| 20 | cached_raw_time_point = raw_time_point; | ||
| 21 | return raw_time_point; | ||
| 22 | } | ||
| 23 | |||
| 24 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_steady_clock_core.h b/src/core/hle/service/time/standard_steady_clock_core.h deleted file mode 100644 index 036463b87..000000000 --- a/src/core/hle/service/time/standard_steady_clock_core.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/clock_types.h" | ||
| 7 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::Time::Clock { | ||
| 14 | |||
| 15 | class StandardSteadyClockCore final : public SteadyClockCore { | ||
| 16 | public: | ||
| 17 | SteadyClockTimePoint GetTimePoint(Core::System& system) override { | ||
| 18 | return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()}; | ||
| 19 | } | ||
| 20 | |||
| 21 | TimeSpanType GetInternalOffset() const override { | ||
| 22 | return internal_offset; | ||
| 23 | } | ||
| 24 | |||
| 25 | void SetInternalOffset(TimeSpanType value) override { | ||
| 26 | internal_offset = value; | ||
| 27 | } | ||
| 28 | |||
| 29 | TimeSpanType GetCurrentRawTimePoint(Core::System& system) override; | ||
| 30 | |||
| 31 | void SetSetupValue(TimeSpanType value) { | ||
| 32 | setup_value = value; | ||
| 33 | } | ||
| 34 | |||
| 35 | private: | ||
| 36 | TimeSpanType setup_value{}; | ||
| 37 | TimeSpanType internal_offset{}; | ||
| 38 | TimeSpanType cached_raw_time_point{}; | ||
| 39 | }; | ||
| 40 | |||
| 41 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp deleted file mode 100644 index b033757ed..000000000 --- a/src/core/hle/service/time/standard_user_system_clock_core.cpp +++ /dev/null | |||
| @@ -1,81 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/assert.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hle/kernel/k_event.h" | ||
| 7 | #include "core/hle/service/time/standard_local_system_clock_core.h" | ||
| 8 | #include "core/hle/service/time/standard_network_system_clock_core.h" | ||
| 9 | #include "core/hle/service/time/standard_user_system_clock_core.h" | ||
| 10 | |||
| 11 | namespace Service::Time::Clock { | ||
| 12 | |||
| 13 | StandardUserSystemClockCore::StandardUserSystemClockCore( | ||
| 14 | StandardLocalSystemClockCore& local_system_clock_core_, | ||
| 15 | StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_) | ||
| 16 | : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()), | ||
| 17 | local_system_clock_core{local_system_clock_core_}, | ||
| 18 | network_system_clock_core{network_system_clock_core_}, | ||
| 19 | auto_correction_time{SteadyClockTimePoint::GetRandom()}, service_context{ | ||
| 20 | system_, | ||
| 21 | "StandardUserSystemClockCore"} { | ||
| 22 | auto_correction_event = | ||
| 23 | service_context.CreateEvent("StandardUserSystemClockCore:AutoCorrectionEvent"); | ||
| 24 | } | ||
| 25 | |||
| 26 | StandardUserSystemClockCore::~StandardUserSystemClockCore() { | ||
| 27 | service_context.CloseEvent(auto_correction_event); | ||
| 28 | } | ||
| 29 | |||
| 30 | Result StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, | ||
| 31 | bool value) { | ||
| 32 | if (const Result result{ApplyAutomaticCorrection(system, value)}; result != ResultSuccess) { | ||
| 33 | return result; | ||
| 34 | } | ||
| 35 | |||
| 36 | auto_correction_enabled = value; | ||
| 37 | |||
| 38 | return ResultSuccess; | ||
| 39 | } | ||
| 40 | |||
| 41 | Result StandardUserSystemClockCore::GetClockContext(Core::System& system, | ||
| 42 | SystemClockContext& ctx) const { | ||
| 43 | if (const Result result{ApplyAutomaticCorrection(system, false)}; result != ResultSuccess) { | ||
| 44 | return result; | ||
| 45 | } | ||
| 46 | |||
| 47 | return local_system_clock_core.GetClockContext(system, ctx); | ||
| 48 | } | ||
| 49 | |||
| 50 | Result StandardUserSystemClockCore::Flush(const SystemClockContext&) { | ||
| 51 | UNIMPLEMENTED(); | ||
| 52 | return ERROR_NOT_IMPLEMENTED; | ||
| 53 | } | ||
| 54 | |||
| 55 | Result StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) { | ||
| 56 | UNIMPLEMENTED(); | ||
| 57 | return ERROR_NOT_IMPLEMENTED; | ||
| 58 | } | ||
| 59 | |||
| 60 | Result StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system, | ||
| 61 | bool value) const { | ||
| 62 | if (auto_correction_enabled == value) { | ||
| 63 | return ResultSuccess; | ||
| 64 | } | ||
| 65 | |||
| 66 | if (!network_system_clock_core.IsClockSetup(system)) { | ||
| 67 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 68 | } | ||
| 69 | |||
| 70 | SystemClockContext ctx{}; | ||
| 71 | if (const Result result{network_system_clock_core.GetClockContext(system, ctx)}; | ||
| 72 | result != ResultSuccess) { | ||
| 73 | return result; | ||
| 74 | } | ||
| 75 | |||
| 76 | local_system_clock_core.SetClockContext(ctx); | ||
| 77 | |||
| 78 | return ResultSuccess; | ||
| 79 | } | ||
| 80 | |||
| 81 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h deleted file mode 100644 index ee6e29487..000000000 --- a/src/core/hle/service/time/standard_user_system_clock_core.h +++ /dev/null | |||
| @@ -1,63 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/kernel_helpers.h" | ||
| 7 | #include "core/hle/service/time/clock_types.h" | ||
| 8 | #include "core/hle/service/time/system_clock_core.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | class KEvent; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::Time::Clock { | ||
| 19 | |||
| 20 | class StandardLocalSystemClockCore; | ||
| 21 | class StandardNetworkSystemClockCore; | ||
| 22 | |||
| 23 | class StandardUserSystemClockCore final : public SystemClockCore { | ||
| 24 | public: | ||
| 25 | StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_, | ||
| 26 | StandardNetworkSystemClockCore& network_system_clock_core_, | ||
| 27 | Core::System& system_); | ||
| 28 | |||
| 29 | ~StandardUserSystemClockCore() override; | ||
| 30 | |||
| 31 | Result SetAutomaticCorrectionEnabled(Core::System& system, bool value); | ||
| 32 | |||
| 33 | Result GetClockContext(Core::System& system, SystemClockContext& ctx) const override; | ||
| 34 | |||
| 35 | bool IsAutomaticCorrectionEnabled() const { | ||
| 36 | return auto_correction_enabled; | ||
| 37 | } | ||
| 38 | |||
| 39 | void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) { | ||
| 40 | auto_correction_time = steady_clock_time_point; | ||
| 41 | } | ||
| 42 | |||
| 43 | protected: | ||
| 44 | Result Flush(const SystemClockContext&) override; | ||
| 45 | |||
| 46 | Result SetClockContext(const SystemClockContext&) override; | ||
| 47 | |||
| 48 | Result ApplyAutomaticCorrection(Core::System& system, bool value) const; | ||
| 49 | |||
| 50 | const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const { | ||
| 51 | return auto_correction_time; | ||
| 52 | } | ||
| 53 | |||
| 54 | private: | ||
| 55 | StandardLocalSystemClockCore& local_system_clock_core; | ||
| 56 | StandardNetworkSystemClockCore& network_system_clock_core; | ||
| 57 | bool auto_correction_enabled{}; | ||
| 58 | SteadyClockTimePoint auto_correction_time; | ||
| 59 | KernelHelpers::ServiceContext service_context; | ||
| 60 | Kernel::KEvent* auto_correction_event; | ||
| 61 | }; | ||
| 62 | |||
| 63 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h deleted file mode 100644 index 2867c351c..000000000 --- a/src/core/hle/service/time/steady_clock_core.h +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/uuid.h" | ||
| 7 | #include "core/hle/service/time/clock_types.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::Time::Clock { | ||
| 14 | |||
| 15 | class SteadyClockCore { | ||
| 16 | public: | ||
| 17 | SteadyClockCore() = default; | ||
| 18 | virtual ~SteadyClockCore() = default; | ||
| 19 | |||
| 20 | const Common::UUID& GetClockSourceId() const { | ||
| 21 | return clock_source_id; | ||
| 22 | } | ||
| 23 | |||
| 24 | void SetClockSourceId(const Common::UUID& value) { | ||
| 25 | clock_source_id = value; | ||
| 26 | } | ||
| 27 | |||
| 28 | virtual TimeSpanType GetInternalOffset() const = 0; | ||
| 29 | |||
| 30 | virtual void SetInternalOffset(TimeSpanType internal_offset) = 0; | ||
| 31 | |||
| 32 | virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0; | ||
| 33 | |||
| 34 | virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0; | ||
| 35 | |||
| 36 | SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) { | ||
| 37 | SteadyClockTimePoint result{GetTimePoint(system)}; | ||
| 38 | result.time_point += GetInternalOffset().ToSeconds(); | ||
| 39 | return result; | ||
| 40 | } | ||
| 41 | |||
| 42 | bool IsInitialized() const { | ||
| 43 | return is_initialized; | ||
| 44 | } | ||
| 45 | |||
| 46 | void MarkAsInitialized() { | ||
| 47 | is_initialized = true; | ||
| 48 | } | ||
| 49 | |||
| 50 | private: | ||
| 51 | Common::UUID clock_source_id{Common::UUID::MakeRandom()}; | ||
| 52 | bool is_initialized{}; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.cpp b/src/core/hle/service/time/system_clock_context_update_callback.cpp deleted file mode 100644 index cafc04ee7..000000000 --- a/src/core/hle/service/time/system_clock_context_update_callback.cpp +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_event.h" | ||
| 5 | #include "core/hle/service/time/errors.h" | ||
| 6 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 7 | |||
| 8 | namespace Service::Time::Clock { | ||
| 9 | |||
| 10 | SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default; | ||
| 11 | SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default; | ||
| 12 | |||
| 13 | bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const { | ||
| 14 | if (has_context) { | ||
| 15 | return context.offset != value.offset || | ||
| 16 | context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id; | ||
| 17 | } | ||
| 18 | |||
| 19 | return true; | ||
| 20 | } | ||
| 21 | |||
| 22 | void SystemClockContextUpdateCallback::RegisterOperationEvent( | ||
| 23 | std::shared_ptr<Kernel::KEvent>&& event) { | ||
| 24 | operation_event_list.emplace_back(std::move(event)); | ||
| 25 | } | ||
| 26 | |||
| 27 | void SystemClockContextUpdateCallback::BroadcastOperationEvent() { | ||
| 28 | for (const auto& event : operation_event_list) { | ||
| 29 | event->Signal(); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | Result SystemClockContextUpdateCallback::Update(const SystemClockContext& value) { | ||
| 34 | Result result{ResultSuccess}; | ||
| 35 | |||
| 36 | if (NeedUpdate(value)) { | ||
| 37 | context = value; | ||
| 38 | has_context = true; | ||
| 39 | |||
| 40 | result = Update(); | ||
| 41 | |||
| 42 | if (result == ResultSuccess) { | ||
| 43 | BroadcastOperationEvent(); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | return result; | ||
| 48 | } | ||
| 49 | |||
| 50 | Result SystemClockContextUpdateCallback::Update() { | ||
| 51 | return ResultSuccess; | ||
| 52 | } | ||
| 53 | |||
| 54 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h deleted file mode 100644 index bf657acd9..000000000 --- a/src/core/hle/service/time/system_clock_context_update_callback.h +++ /dev/null | |||
| @@ -1,43 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "core/hle/service/time/clock_types.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | class KEvent; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Time::Clock { | ||
| 16 | |||
| 17 | // Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). | ||
| 18 | // This code was released under public domain. | ||
| 19 | |||
| 20 | class SystemClockContextUpdateCallback { | ||
| 21 | public: | ||
| 22 | SystemClockContextUpdateCallback(); | ||
| 23 | virtual ~SystemClockContextUpdateCallback(); | ||
| 24 | |||
| 25 | bool NeedUpdate(const SystemClockContext& value) const; | ||
| 26 | |||
| 27 | void RegisterOperationEvent(std::shared_ptr<Kernel::KEvent>&& event); | ||
| 28 | |||
| 29 | void BroadcastOperationEvent(); | ||
| 30 | |||
| 31 | Result Update(const SystemClockContext& value); | ||
| 32 | |||
| 33 | protected: | ||
| 34 | virtual Result Update(); | ||
| 35 | |||
| 36 | SystemClockContext context{}; | ||
| 37 | |||
| 38 | private: | ||
| 39 | bool has_context{}; | ||
| 40 | std::vector<std::shared_ptr<Kernel::KEvent>> operation_event_list; | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp deleted file mode 100644 index da078241f..000000000 --- a/src/core/hle/service/time/system_clock_core.cpp +++ /dev/null | |||
| @@ -1,71 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 5 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 6 | #include "core/hle/service/time/system_clock_core.h" | ||
| 7 | |||
| 8 | namespace Service::Time::Clock { | ||
| 9 | |||
| 10 | SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_) | ||
| 11 | : steady_clock_core{steady_clock_core_} { | ||
| 12 | context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId(); | ||
| 13 | } | ||
| 14 | |||
| 15 | SystemClockCore::~SystemClockCore() = default; | ||
| 16 | |||
| 17 | Result SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const { | ||
| 18 | posix_time = 0; | ||
| 19 | |||
| 20 | const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 21 | |||
| 22 | SystemClockContext clock_context{}; | ||
| 23 | if (const Result result{GetClockContext(system, clock_context)}; result != ResultSuccess) { | ||
| 24 | return result; | ||
| 25 | } | ||
| 26 | |||
| 27 | if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) { | ||
| 28 | return ERROR_TIME_MISMATCH; | ||
| 29 | } | ||
| 30 | |||
| 31 | posix_time = clock_context.offset + current_time_point.time_point; | ||
| 32 | |||
| 33 | return ResultSuccess; | ||
| 34 | } | ||
| 35 | |||
| 36 | Result SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) { | ||
| 37 | const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 38 | const SystemClockContext clock_context{posix_time - current_time_point.time_point, | ||
| 39 | current_time_point}; | ||
| 40 | |||
| 41 | if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) { | ||
| 42 | return result; | ||
| 43 | } | ||
| 44 | return Flush(clock_context); | ||
| 45 | } | ||
| 46 | |||
| 47 | Result SystemClockCore::Flush(const SystemClockContext& clock_context) { | ||
| 48 | if (!system_clock_context_update_callback) { | ||
| 49 | return ResultSuccess; | ||
| 50 | } | ||
| 51 | return system_clock_context_update_callback->Update(clock_context); | ||
| 52 | } | ||
| 53 | |||
| 54 | Result SystemClockCore::SetSystemClockContext(const SystemClockContext& clock_context) { | ||
| 55 | if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) { | ||
| 56 | return result; | ||
| 57 | } | ||
| 58 | return Flush(clock_context); | ||
| 59 | } | ||
| 60 | |||
| 61 | bool SystemClockCore::IsClockSetup(Core::System& system) const { | ||
| 62 | SystemClockContext value{}; | ||
| 63 | if (GetClockContext(system, value) == ResultSuccess) { | ||
| 64 | const SteadyClockTimePoint steady_clock_time_point{ | ||
| 65 | steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 66 | return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id; | ||
| 67 | } | ||
| 68 | return {}; | ||
| 69 | } | ||
| 70 | |||
| 71 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h deleted file mode 100644 index 8cb34126f..000000000 --- a/src/core/hle/service/time/system_clock_core.h +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/service/time/clock_types.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Time::Clock { | ||
| 16 | |||
| 17 | class SteadyClockCore; | ||
| 18 | class SystemClockContextUpdateCallback; | ||
| 19 | |||
| 20 | // Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). | ||
| 21 | // This code was released under public domain. | ||
| 22 | |||
| 23 | class SystemClockCore { | ||
| 24 | public: | ||
| 25 | explicit SystemClockCore(SteadyClockCore& steady_clock_core_); | ||
| 26 | virtual ~SystemClockCore(); | ||
| 27 | |||
| 28 | SteadyClockCore& GetSteadyClockCore() const { | ||
| 29 | return steady_clock_core; | ||
| 30 | } | ||
| 31 | |||
| 32 | Result GetCurrentTime(Core::System& system, s64& posix_time) const; | ||
| 33 | |||
| 34 | Result SetCurrentTime(Core::System& system, s64 posix_time); | ||
| 35 | |||
| 36 | virtual Result GetClockContext([[maybe_unused]] Core::System& system, | ||
| 37 | SystemClockContext& value) const { | ||
| 38 | value = context; | ||
| 39 | return ResultSuccess; | ||
| 40 | } | ||
| 41 | |||
| 42 | virtual Result SetClockContext(const SystemClockContext& value) { | ||
| 43 | context = value; | ||
| 44 | return ResultSuccess; | ||
| 45 | } | ||
| 46 | |||
| 47 | virtual Result Flush(const SystemClockContext& clock_context); | ||
| 48 | |||
| 49 | void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) { | ||
| 50 | system_clock_context_update_callback = std::move(callback); | ||
| 51 | } | ||
| 52 | |||
| 53 | Result SetSystemClockContext(const SystemClockContext& context); | ||
| 54 | |||
| 55 | bool IsInitialized() const { | ||
| 56 | return is_initialized; | ||
| 57 | } | ||
| 58 | |||
| 59 | void MarkAsInitialized() { | ||
| 60 | is_initialized = true; | ||
| 61 | } | ||
| 62 | |||
| 63 | bool IsClockSetup(Core::System& system) const; | ||
| 64 | |||
| 65 | private: | ||
| 66 | SteadyClockCore& steady_clock_core; | ||
| 67 | SystemClockContext context{}; | ||
| 68 | bool is_initialized{}; | ||
| 69 | std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback; | ||
| 70 | }; | ||
| 71 | |||
| 72 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp deleted file mode 100644 index 0d9fb3143..000000000 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hardware_properties.h" | ||
| 7 | #include "core/hle/service/time/tick_based_steady_clock_core.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { | ||
| 12 | const TimeSpanType ticks_time_span{ | ||
| 13 | TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())}; | ||
| 14 | |||
| 15 | return {ticks_time_span.ToSeconds(), GetClockSourceId()}; | ||
| 16 | } | ||
| 17 | |||
| 18 | TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { | ||
| 19 | return TimeSpanType::FromSeconds(GetTimePoint(system).time_point); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.h b/src/core/hle/service/time/tick_based_steady_clock_core.h deleted file mode 100644 index 491185dc3..000000000 --- a/src/core/hle/service/time/tick_based_steady_clock_core.h +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/clock_types.h" | ||
| 7 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::Time::Clock { | ||
| 14 | |||
| 15 | class TickBasedSteadyClockCore final : public SteadyClockCore { | ||
| 16 | public: | ||
| 17 | TimeSpanType GetInternalOffset() const override { | ||
| 18 | return {}; | ||
| 19 | } | ||
| 20 | |||
| 21 | void SetInternalOffset(TimeSpanType internal_offset) override {} | ||
| 22 | |||
| 23 | SteadyClockTimePoint GetTimePoint(Core::System& system) override; | ||
| 24 | |||
| 25 | TimeSpanType GetCurrentRawTimePoint(Core::System& system) override; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp deleted file mode 100644 index 7197ca30f..000000000 --- a/src/core/hle/service/time/time.cpp +++ /dev/null | |||
| @@ -1,412 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hardware_properties.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | ||
| 9 | #include "core/hle/service/ipc_helpers.h" | ||
| 10 | #include "core/hle/service/server_manager.h" | ||
| 11 | #include "core/hle/service/time/time.h" | ||
| 12 | #include "core/hle/service/time/time_interface.h" | ||
| 13 | #include "core/hle/service/time/time_manager.h" | ||
| 14 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 15 | #include "core/hle/service/time/time_zone_service.h" | ||
| 16 | |||
| 17 | namespace Service::Time { | ||
| 18 | |||
| 19 | class ISystemClock final : public ServiceFramework<ISystemClock> { | ||
| 20 | public: | ||
| 21 | explicit ISystemClock(Clock::SystemClockCore& clock_core_, Core::System& system_) | ||
| 22 | : ServiceFramework{system_, "ISystemClock"}, clock_core{clock_core_} { | ||
| 23 | // clang-format off | ||
| 24 | static const FunctionInfo functions[] = { | ||
| 25 | {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, | ||
| 26 | {1, nullptr, "SetCurrentTime"}, | ||
| 27 | {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, | ||
| 28 | {3, nullptr, "SetSystemClockContext"}, | ||
| 29 | {4, nullptr, "GetOperationEventReadableHandle"}, | ||
| 30 | }; | ||
| 31 | // clang-format on | ||
| 32 | |||
| 33 | RegisterHandlers(functions); | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | void GetCurrentTime(HLERequestContext& ctx) { | ||
| 38 | LOG_DEBUG(Service_Time, "called"); | ||
| 39 | |||
| 40 | if (!clock_core.IsInitialized()) { | ||
| 41 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 42 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | s64 posix_time{}; | ||
| 47 | if (const Result result{clock_core.GetCurrentTime(system, posix_time)}; result.IsError()) { | ||
| 48 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 49 | rb.Push(result); | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | |||
| 53 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 54 | rb.Push(ResultSuccess); | ||
| 55 | rb.Push<s64>(posix_time); | ||
| 56 | } | ||
| 57 | |||
| 58 | void GetSystemClockContext(HLERequestContext& ctx) { | ||
| 59 | LOG_DEBUG(Service_Time, "called"); | ||
| 60 | |||
| 61 | if (!clock_core.IsInitialized()) { | ||
| 62 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 63 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | |||
| 67 | Clock::SystemClockContext system_clock_context{}; | ||
| 68 | if (const Result result{clock_core.GetClockContext(system, system_clock_context)}; | ||
| 69 | result.IsError()) { | ||
| 70 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 71 | rb.Push(result); | ||
| 72 | return; | ||
| 73 | } | ||
| 74 | |||
| 75 | IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2}; | ||
| 76 | rb.Push(ResultSuccess); | ||
| 77 | rb.PushRaw(system_clock_context); | ||
| 78 | } | ||
| 79 | |||
| 80 | Clock::SystemClockCore& clock_core; | ||
| 81 | }; | ||
| 82 | |||
| 83 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { | ||
| 84 | public: | ||
| 85 | explicit ISteadyClock(Clock::SteadyClockCore& clock_core_, Core::System& system_) | ||
| 86 | : ServiceFramework{system_, "ISteadyClock"}, clock_core{clock_core_} { | ||
| 87 | static const FunctionInfo functions[] = { | ||
| 88 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, | ||
| 89 | {2, nullptr, "GetTestOffset"}, | ||
| 90 | {3, nullptr, "SetTestOffset"}, | ||
| 91 | {100, nullptr, "GetRtcValue"}, | ||
| 92 | {101, nullptr, "IsRtcResetDetected"}, | ||
| 93 | {102, nullptr, "GetSetupResultValue"}, | ||
| 94 | {200, nullptr, "GetInternalOffset"}, | ||
| 95 | {201, nullptr, "SetInternalOffset"}, | ||
| 96 | }; | ||
| 97 | RegisterHandlers(functions); | ||
| 98 | } | ||
| 99 | |||
| 100 | private: | ||
| 101 | void GetCurrentTimePoint(HLERequestContext& ctx) { | ||
| 102 | LOG_DEBUG(Service_Time, "called"); | ||
| 103 | |||
| 104 | if (!clock_core.IsInitialized()) { | ||
| 105 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 106 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | |||
| 110 | const Clock::SteadyClockTimePoint time_point{clock_core.GetCurrentTimePoint(system)}; | ||
| 111 | IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2}; | ||
| 112 | rb.Push(ResultSuccess); | ||
| 113 | rb.PushRaw(time_point); | ||
| 114 | } | ||
| 115 | |||
| 116 | Clock::SteadyClockCore& clock_core; | ||
| 117 | }; | ||
| 118 | |||
| 119 | Result Module::Interface::GetClockSnapshotFromSystemClockContextInternal( | ||
| 120 | Kernel::KThread* thread, Clock::SystemClockContext user_context, | ||
| 121 | Clock::SystemClockContext network_context, Clock::TimeType type, | ||
| 122 | Clock::ClockSnapshot& clock_snapshot) { | ||
| 123 | |||
| 124 | auto& time_manager{system.GetTimeManager()}; | ||
| 125 | |||
| 126 | clock_snapshot.steady_clock_time_point = | ||
| 127 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system); | ||
| 128 | clock_snapshot.is_automatic_correction_enabled = | ||
| 129 | time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); | ||
| 130 | clock_snapshot.type = type; | ||
| 131 | |||
| 132 | if (const Result result{ | ||
| 133 | time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName( | ||
| 134 | clock_snapshot.location_name)}; | ||
| 135 | result != ResultSuccess) { | ||
| 136 | return result; | ||
| 137 | } | ||
| 138 | |||
| 139 | clock_snapshot.user_context = user_context; | ||
| 140 | |||
| 141 | if (const Result result{Clock::ClockSnapshot::GetCurrentTime( | ||
| 142 | clock_snapshot.user_time, clock_snapshot.steady_clock_time_point, | ||
| 143 | clock_snapshot.user_context)}; | ||
| 144 | result != ResultSuccess) { | ||
| 145 | return result; | ||
| 146 | } | ||
| 147 | |||
| 148 | TimeZone::CalendarInfo userCalendarInfo{}; | ||
| 149 | if (const Result result{ | ||
| 150 | time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules( | ||
| 151 | clock_snapshot.user_time, userCalendarInfo)}; | ||
| 152 | result != ResultSuccess) { | ||
| 153 | return result; | ||
| 154 | } | ||
| 155 | |||
| 156 | clock_snapshot.user_calendar_time = userCalendarInfo.time; | ||
| 157 | clock_snapshot.user_calendar_additional_time = userCalendarInfo.additional_info; | ||
| 158 | |||
| 159 | clock_snapshot.network_context = network_context; | ||
| 160 | |||
| 161 | if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, | ||
| 162 | clock_snapshot.steady_clock_time_point, | ||
| 163 | clock_snapshot.network_context) != ResultSuccess) { | ||
| 164 | clock_snapshot.network_time = 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | TimeZone::CalendarInfo networkCalendarInfo{}; | ||
| 168 | if (const Result result{ | ||
| 169 | time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules( | ||
| 170 | clock_snapshot.network_time, networkCalendarInfo)}; | ||
| 171 | result != ResultSuccess) { | ||
| 172 | return result; | ||
| 173 | } | ||
| 174 | |||
| 175 | clock_snapshot.network_calendar_time = networkCalendarInfo.time; | ||
| 176 | clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additional_info; | ||
| 177 | |||
| 178 | return ResultSuccess; | ||
| 179 | } | ||
| 180 | |||
| 181 | void Module::Interface::GetStandardUserSystemClock(HLERequestContext& ctx) { | ||
| 182 | LOG_DEBUG(Service_Time, "called"); | ||
| 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 184 | rb.Push(ResultSuccess); | ||
| 185 | rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(), | ||
| 186 | system); | ||
| 187 | } | ||
| 188 | |||
| 189 | void Module::Interface::GetStandardNetworkSystemClock(HLERequestContext& ctx) { | ||
| 190 | LOG_DEBUG(Service_Time, "called"); | ||
| 191 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 192 | rb.Push(ResultSuccess); | ||
| 193 | rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(), | ||
| 194 | system); | ||
| 195 | } | ||
| 196 | |||
| 197 | void Module::Interface::GetStandardSteadyClock(HLERequestContext& ctx) { | ||
| 198 | LOG_DEBUG(Service_Time, "called"); | ||
| 199 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 200 | rb.Push(ResultSuccess); | ||
| 201 | rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system); | ||
| 202 | } | ||
| 203 | |||
| 204 | void Module::Interface::GetTimeZoneService(HLERequestContext& ctx) { | ||
| 205 | LOG_DEBUG(Service_Time, "called"); | ||
| 206 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 207 | rb.Push(ResultSuccess); | ||
| 208 | rb.PushIpcInterface<ITimeZoneService>(system, | ||
| 209 | system.GetTimeManager().GetTimeZoneContentManager()); | ||
| 210 | } | ||
| 211 | |||
| 212 | void Module::Interface::GetStandardLocalSystemClock(HLERequestContext& ctx) { | ||
| 213 | LOG_DEBUG(Service_Time, "called"); | ||
| 214 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 215 | rb.Push(ResultSuccess); | ||
| 216 | rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(), | ||
| 217 | system); | ||
| 218 | } | ||
| 219 | |||
| 220 | void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { | ||
| 221 | LOG_DEBUG(Service_Time, "called"); | ||
| 222 | auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()}; | ||
| 223 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 224 | rb.Push(ResultSuccess); | ||
| 225 | rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); | ||
| 226 | } | ||
| 227 | |||
| 228 | void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { | ||
| 229 | LOG_DEBUG(Service_Time, "called"); | ||
| 230 | |||
| 231 | auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()}; | ||
| 232 | if (!steady_clock_core.IsInitialized()) { | ||
| 233 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 234 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | ||
| 235 | return; | ||
| 236 | } | ||
| 237 | |||
| 238 | IPC::RequestParser rp{ctx}; | ||
| 239 | const auto context{rp.PopRaw<Clock::SystemClockContext>()}; | ||
| 240 | const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 241 | |||
| 242 | if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { | ||
| 243 | const auto ticks{Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>( | ||
| 244 | system.CoreTiming().GetClockTicks())}; | ||
| 245 | const s64 base_time_point{context.offset + current_time_point.time_point - | ||
| 246 | ticks.ToSeconds()}; | ||
| 247 | IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; | ||
| 248 | rb.Push(ResultSuccess); | ||
| 249 | rb.PushRaw(base_time_point); | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | |||
| 253 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 254 | rb.Push(ERROR_TIME_MISMATCH); | ||
| 255 | } | ||
| 256 | |||
| 257 | void Module::Interface::GetClockSnapshot(HLERequestContext& ctx) { | ||
| 258 | IPC::RequestParser rp{ctx}; | ||
| 259 | const auto type{rp.PopEnum<Clock::TimeType>()}; | ||
| 260 | |||
| 261 | LOG_DEBUG(Service_Time, "called, type={}", type); | ||
| 262 | |||
| 263 | Clock::SystemClockContext user_context{}; | ||
| 264 | if (const Result result{ | ||
| 265 | system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system, | ||
| 266 | user_context)}; | ||
| 267 | result.IsError()) { | ||
| 268 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 269 | rb.Push(result); | ||
| 270 | return; | ||
| 271 | } | ||
| 272 | |||
| 273 | Clock::SystemClockContext network_context{}; | ||
| 274 | if (const Result result{ | ||
| 275 | system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( | ||
| 276 | system, network_context)}; | ||
| 277 | result.IsError()) { | ||
| 278 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 279 | rb.Push(result); | ||
| 280 | return; | ||
| 281 | } | ||
| 282 | |||
| 283 | Clock::ClockSnapshot clock_snapshot{}; | ||
| 284 | if (const Result result{GetClockSnapshotFromSystemClockContextInternal( | ||
| 285 | &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; | ||
| 286 | result.IsError()) { | ||
| 287 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 288 | rb.Push(result); | ||
| 289 | return; | ||
| 290 | } | ||
| 291 | |||
| 292 | ctx.WriteBuffer(clock_snapshot); | ||
| 293 | |||
| 294 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 295 | rb.Push(ResultSuccess); | ||
| 296 | } | ||
| 297 | |||
| 298 | void Module::Interface::GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { | ||
| 299 | IPC::RequestParser rp{ctx}; | ||
| 300 | const auto type{rp.PopEnum<Clock::TimeType>()}; | ||
| 301 | |||
| 302 | rp.Skip(1, false); | ||
| 303 | |||
| 304 | const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()}; | ||
| 305 | const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()}; | ||
| 306 | |||
| 307 | LOG_DEBUG(Service_Time, "called, type={}", type); | ||
| 308 | |||
| 309 | Clock::ClockSnapshot clock_snapshot{}; | ||
| 310 | if (const Result result{GetClockSnapshotFromSystemClockContextInternal( | ||
| 311 | &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; | ||
| 312 | result != ResultSuccess) { | ||
| 313 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 314 | rb.Push(result); | ||
| 315 | return; | ||
| 316 | } | ||
| 317 | |||
| 318 | ctx.WriteBuffer(clock_snapshot); | ||
| 319 | |||
| 320 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 321 | rb.Push(ResultSuccess); | ||
| 322 | } | ||
| 323 | |||
| 324 | void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx) { | ||
| 325 | LOG_DEBUG(Service_Time, "called"); | ||
| 326 | |||
| 327 | Clock::ClockSnapshot snapshot_a; | ||
| 328 | Clock::ClockSnapshot snapshot_b; | ||
| 329 | |||
| 330 | const auto snapshot_a_data = ctx.ReadBuffer(0); | ||
| 331 | const auto snapshot_b_data = ctx.ReadBuffer(1); | ||
| 332 | |||
| 333 | std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot)); | ||
| 334 | std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot)); | ||
| 335 | |||
| 336 | auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset - | ||
| 337 | snapshot_a.user_context.offset)}; | ||
| 338 | |||
| 339 | if ((snapshot_b.user_context.steady_time_point.clock_source_id != | ||
| 340 | snapshot_a.user_context.steady_time_point.clock_source_id) || | ||
| 341 | (snapshot_b.is_automatic_correction_enabled && | ||
| 342 | snapshot_a.is_automatic_correction_enabled)) { | ||
| 343 | time_span_type.nanoseconds = 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; | ||
| 347 | rb.Push(ResultSuccess); | ||
| 348 | rb.PushRaw(time_span_type.nanoseconds); | ||
| 349 | } | ||
| 350 | |||
| 351 | void Module::Interface::CalculateSpanBetween(HLERequestContext& ctx) { | ||
| 352 | LOG_DEBUG(Service_Time, "called"); | ||
| 353 | |||
| 354 | Clock::ClockSnapshot snapshot_a; | ||
| 355 | Clock::ClockSnapshot snapshot_b; | ||
| 356 | |||
| 357 | const auto snapshot_a_data = ctx.ReadBuffer(0); | ||
| 358 | const auto snapshot_b_data = ctx.ReadBuffer(1); | ||
| 359 | |||
| 360 | std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot)); | ||
| 361 | std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot)); | ||
| 362 | |||
| 363 | Clock::TimeSpanType time_span_type{}; | ||
| 364 | s64 span{}; | ||
| 365 | |||
| 366 | if (const Result result{snapshot_a.steady_clock_time_point.GetSpanBetween( | ||
| 367 | snapshot_b.steady_clock_time_point, span)}; | ||
| 368 | result != ResultSuccess) { | ||
| 369 | if (snapshot_a.network_time && snapshot_b.network_time) { | ||
| 370 | time_span_type = | ||
| 371 | Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time); | ||
| 372 | } else { | ||
| 373 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 374 | rb.Push(ERROR_TIME_NOT_FOUND); | ||
| 375 | return; | ||
| 376 | } | ||
| 377 | } else { | ||
| 378 | time_span_type = Clock::TimeSpanType::FromSeconds(span); | ||
| 379 | } | ||
| 380 | |||
| 381 | IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; | ||
| 382 | rb.Push(ResultSuccess); | ||
| 383 | rb.PushRaw(time_span_type.nanoseconds); | ||
| 384 | } | ||
| 385 | |||
| 386 | void Module::Interface::GetSharedMemoryNativeHandle(HLERequestContext& ctx) { | ||
| 387 | LOG_DEBUG(Service_Time, "called"); | ||
| 388 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 389 | rb.Push(ResultSuccess); | ||
| 390 | rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem()); | ||
| 391 | } | ||
| 392 | |||
| 393 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, | ||
| 394 | const char* name) | ||
| 395 | : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||
| 396 | |||
| 397 | Module::Interface::~Interface() = default; | ||
| 398 | |||
| 399 | void LoopProcess(Core::System& system) { | ||
| 400 | auto server_manager = std::make_unique<ServerManager>(system); | ||
| 401 | auto module{std::make_shared<Module>()}; | ||
| 402 | |||
| 403 | server_manager->RegisterNamedService("time:a", | ||
| 404 | std::make_shared<Time>(module, system, "time:a")); | ||
| 405 | server_manager->RegisterNamedService("time:s", | ||
| 406 | std::make_shared<Time>(module, system, "time:s")); | ||
| 407 | server_manager->RegisterNamedService("time:u", | ||
| 408 | std::make_shared<Time>(module, system, "time:u")); | ||
| 409 | ServerManager::RunServer(std::move(server_manager)); | ||
| 410 | } | ||
| 411 | |||
| 412 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h deleted file mode 100644 index b2d754ef3..000000000 --- a/src/core/hle/service/time/time.h +++ /dev/null | |||
| @@ -1,51 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | #include "core/hle/service/time/clock_types.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::Time { | ||
| 14 | |||
| 15 | class Module final { | ||
| 16 | public: | ||
| 17 | Module() = default; | ||
| 18 | |||
| 19 | class Interface : public ServiceFramework<Interface> { | ||
| 20 | public: | ||
| 21 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, | ||
| 22 | const char* name); | ||
| 23 | ~Interface() override; | ||
| 24 | |||
| 25 | void GetStandardUserSystemClock(HLERequestContext& ctx); | ||
| 26 | void GetStandardNetworkSystemClock(HLERequestContext& ctx); | ||
| 27 | void GetStandardSteadyClock(HLERequestContext& ctx); | ||
| 28 | void GetTimeZoneService(HLERequestContext& ctx); | ||
| 29 | void GetStandardLocalSystemClock(HLERequestContext& ctx); | ||
| 30 | void IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); | ||
| 31 | void CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); | ||
| 32 | void GetClockSnapshot(HLERequestContext& ctx); | ||
| 33 | void GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); | ||
| 34 | void CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); | ||
| 35 | void CalculateSpanBetween(HLERequestContext& ctx); | ||
| 36 | void GetSharedMemoryNativeHandle(HLERequestContext& ctx); | ||
| 37 | |||
| 38 | private: | ||
| 39 | Result GetClockSnapshotFromSystemClockContextInternal( | ||
| 40 | Kernel::KThread* thread, Clock::SystemClockContext user_context, | ||
| 41 | Clock::SystemClockContext network_context, Clock::TimeType type, | ||
| 42 | Clock::ClockSnapshot& cloc_snapshot); | ||
| 43 | |||
| 44 | protected: | ||
| 45 | std::shared_ptr<Module> module; | ||
| 46 | }; | ||
| 47 | }; | ||
| 48 | |||
| 49 | void LoopProcess(Core::System& system); | ||
| 50 | |||
| 51 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_interface.cpp b/src/core/hle/service/time/time_interface.cpp deleted file mode 100644 index 0c53e98ee..000000000 --- a/src/core/hle/service/time/time_interface.cpp +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/time/time_interface.h" | ||
| 5 | |||
| 6 | namespace Service::Time { | ||
| 7 | |||
| 8 | Time::Time(std::shared_ptr<Module> module_, Core::System& system_, const char* name_) | ||
| 9 | : Interface{std::move(module_), system_, name_} { | ||
| 10 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | ||
| 13 | {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | ||
| 14 | {2, &Time::GetStandardSteadyClock, "GetStandardSteadyClock"}, | ||
| 15 | {3, &Time::GetTimeZoneService, "GetTimeZoneService"}, | ||
| 16 | {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | ||
| 17 | {5, nullptr, "GetEphemeralNetworkSystemClock"}, | ||
| 18 | {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, | ||
| 19 | {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"}, | ||
| 20 | {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, | ||
| 21 | {50, nullptr, "SetStandardSteadyClockInternalOffset"}, | ||
| 22 | {51, nullptr, "GetStandardSteadyClockRtcValue"}, | ||
| 23 | {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 24 | {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 25 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, | ||
| 26 | {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, | ||
| 27 | {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, | ||
| 28 | {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, | ||
| 29 | {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, | ||
| 30 | {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, | ||
| 31 | {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, | ||
| 32 | {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"}, | ||
| 33 | }; | ||
| 34 | // clang-format on | ||
| 35 | |||
| 36 | RegisterHandlers(functions); | ||
| 37 | } | ||
| 38 | |||
| 39 | Time::~Time() = default; | ||
| 40 | |||
| 41 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_interface.h b/src/core/hle/service/time/time_interface.h deleted file mode 100644 index ceeb0e5ef..000000000 --- a/src/core/hle/service/time/time_interface.h +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/time/time.h" | ||
| 7 | |||
| 8 | namespace Core { | ||
| 9 | class System; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service::Time { | ||
| 13 | |||
| 14 | class Time final : public Module::Interface { | ||
| 15 | public: | ||
| 16 | explicit Time(std::shared_ptr<Module> time, Core::System& system_, const char* name_); | ||
| 17 | ~Time() override; | ||
| 18 | }; | ||
| 19 | |||
| 20 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp deleted file mode 100644 index fa0fd0531..000000000 --- a/src/core/hle/service/time/time_manager.cpp +++ /dev/null | |||
| @@ -1,293 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | #include <ctime> | ||
| 6 | |||
| 7 | #include "common/settings.h" | ||
| 8 | #include "common/time_zone.h" | ||
| 9 | #include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" | ||
| 10 | #include "core/hle/service/time/ephemeral_network_system_clock_core.h" | ||
| 11 | #include "core/hle/service/time/local_system_clock_context_writer.h" | ||
| 12 | #include "core/hle/service/time/network_system_clock_context_writer.h" | ||
| 13 | #include "core/hle/service/time/tick_based_steady_clock_core.h" | ||
| 14 | #include "core/hle/service/time/time_manager.h" | ||
| 15 | |||
| 16 | namespace Service::Time { | ||
| 17 | namespace { | ||
| 18 | constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL}; | ||
| 19 | |||
| 20 | s64 GetSecondsSinceEpoch() { | ||
| 21 | const auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch(); | ||
| 22 | return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() + | ||
| 23 | Settings::values.custom_rtc_differential; | ||
| 24 | } | ||
| 25 | } // Anonymous namespace | ||
| 26 | |||
| 27 | struct TimeManager::Impl final { | ||
| 28 | explicit Impl(Core::System& system) | ||
| 29 | : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core}, | ||
| 30 | standard_network_system_clock_core{standard_steady_clock_core}, | ||
| 31 | standard_user_system_clock_core{standard_local_system_clock_core, | ||
| 32 | standard_network_system_clock_core, system}, | ||
| 33 | ephemeral_network_system_clock_core{tick_based_steady_clock_core}, | ||
| 34 | local_system_clock_context_writer{ | ||
| 35 | std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)}, | ||
| 36 | network_system_clock_context_writer{ | ||
| 37 | std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)}, | ||
| 38 | ephemeral_network_system_clock_context_writer{ | ||
| 39 | std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, | ||
| 40 | time_zone_content_manager{system} { | ||
| 41 | |||
| 42 | const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())}; | ||
| 43 | SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); | ||
| 44 | SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); | ||
| 45 | |||
| 46 | Clock::SystemClockContext clock_context{}; | ||
| 47 | standard_local_system_clock_core.GetClockContext(system, clock_context); | ||
| 48 | |||
| 49 | SetupStandardNetworkSystemClock(clock_context, standard_network_clock_accuracy); | ||
| 50 | SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom()); | ||
| 51 | SetupEphemeralNetworkSystemClock(); | ||
| 52 | } | ||
| 53 | |||
| 54 | ~Impl() = default; | ||
| 55 | |||
| 56 | Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { | ||
| 57 | return standard_steady_clock_core; | ||
| 58 | } | ||
| 59 | |||
| 60 | const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { | ||
| 61 | return standard_steady_clock_core; | ||
| 62 | } | ||
| 63 | |||
| 64 | Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { | ||
| 65 | return standard_local_system_clock_core; | ||
| 66 | } | ||
| 67 | |||
| 68 | const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { | ||
| 69 | return standard_local_system_clock_core; | ||
| 70 | } | ||
| 71 | |||
| 72 | Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { | ||
| 73 | return standard_network_system_clock_core; | ||
| 74 | } | ||
| 75 | |||
| 76 | const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { | ||
| 77 | return standard_network_system_clock_core; | ||
| 78 | } | ||
| 79 | |||
| 80 | Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { | ||
| 81 | return standard_user_system_clock_core; | ||
| 82 | } | ||
| 83 | |||
| 84 | const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { | ||
| 85 | return standard_user_system_clock_core; | ||
| 86 | } | ||
| 87 | |||
| 88 | TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { | ||
| 89 | return time_zone_content_manager; | ||
| 90 | } | ||
| 91 | |||
| 92 | const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { | ||
| 93 | return time_zone_content_manager; | ||
| 94 | } | ||
| 95 | |||
| 96 | SharedMemory& GetSharedMemory() { | ||
| 97 | return shared_memory; | ||
| 98 | } | ||
| 99 | |||
| 100 | const SharedMemory& GetSharedMemory() const { | ||
| 101 | return shared_memory; | ||
| 102 | } | ||
| 103 | |||
| 104 | void SetupTimeZoneManager(std::string location_name, | ||
| 105 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 106 | std::vector<std::string> location_names, u128 time_zone_rule_version, | ||
| 107 | FileSys::VirtualFile& vfs_file) { | ||
| 108 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( | ||
| 109 | location_name, vfs_file) != ResultSuccess) { | ||
| 110 | ASSERT(false); | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | |||
| 114 | time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); | ||
| 115 | time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( | ||
| 116 | location_names.size()); | ||
| 117 | time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names); | ||
| 118 | time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion( | ||
| 119 | time_zone_rule_version); | ||
| 120 | time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); | ||
| 121 | } | ||
| 122 | |||
| 123 | void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id, | ||
| 124 | Clock::TimeSpanType setup_value, | ||
| 125 | Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { | ||
| 126 | standard_steady_clock_core.SetClockSourceId(clock_source_id); | ||
| 127 | standard_steady_clock_core.SetSetupValue(setup_value); | ||
| 128 | standard_steady_clock_core.SetInternalOffset(internal_offset); | ||
| 129 | standard_steady_clock_core.MarkAsInitialized(); | ||
| 130 | |||
| 131 | const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system_)}; | ||
| 132 | shared_memory.SetupStandardSteadyClock(clock_source_id, current_time_point); | ||
| 133 | } | ||
| 134 | |||
| 135 | void SetupStandardLocalSystemClock(Core::System& system_, | ||
| 136 | Clock::SystemClockContext clock_context, s64 posix_time) { | ||
| 137 | standard_local_system_clock_core.SetUpdateCallbackInstance( | ||
| 138 | local_system_clock_context_writer); | ||
| 139 | |||
| 140 | const auto current_time_point{ | ||
| 141 | standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system_)}; | ||
| 142 | if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { | ||
| 143 | standard_local_system_clock_core.SetSystemClockContext(clock_context); | ||
| 144 | } else { | ||
| 145 | if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) != | ||
| 146 | ResultSuccess) { | ||
| 147 | ASSERT(false); | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | standard_local_system_clock_core.MarkAsInitialized(); | ||
| 153 | } | ||
| 154 | |||
| 155 | void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, | ||
| 156 | Clock::TimeSpanType sufficient_accuracy) { | ||
| 157 | standard_network_system_clock_core.SetUpdateCallbackInstance( | ||
| 158 | network_system_clock_context_writer); | ||
| 159 | |||
| 160 | if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != | ||
| 161 | ResultSuccess) { | ||
| 162 | ASSERT(false); | ||
| 163 | return; | ||
| 164 | } | ||
| 165 | |||
| 166 | standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( | ||
| 167 | sufficient_accuracy); | ||
| 168 | standard_network_system_clock_core.MarkAsInitialized(); | ||
| 169 | } | ||
| 170 | |||
| 171 | void SetupStandardUserSystemClock(Core::System& system_, bool is_automatic_correction_enabled, | ||
| 172 | Clock::SteadyClockTimePoint steady_clock_time_point) { | ||
| 173 | if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( | ||
| 174 | system_, is_automatic_correction_enabled) != ResultSuccess) { | ||
| 175 | ASSERT(false); | ||
| 176 | return; | ||
| 177 | } | ||
| 178 | |||
| 179 | standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); | ||
| 180 | standard_user_system_clock_core.MarkAsInitialized(); | ||
| 181 | shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); | ||
| 182 | } | ||
| 183 | |||
| 184 | void SetupEphemeralNetworkSystemClock() { | ||
| 185 | ephemeral_network_system_clock_core.SetUpdateCallbackInstance( | ||
| 186 | ephemeral_network_system_clock_context_writer); | ||
| 187 | ephemeral_network_system_clock_core.MarkAsInitialized(); | ||
| 188 | } | ||
| 189 | |||
| 190 | void UpdateLocalSystemClockTime(Core::System& system_, s64 posix_time) { | ||
| 191 | const auto timespan{Clock::TimeSpanType::FromSeconds(posix_time)}; | ||
| 192 | if (GetStandardLocalSystemClockCore() | ||
| 193 | .SetCurrentTime(system_, timespan.ToSeconds()) | ||
| 194 | .IsError()) { | ||
| 195 | ASSERT(false); | ||
| 196 | return; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | SharedMemory shared_memory; | ||
| 201 | |||
| 202 | Clock::StandardSteadyClockCore standard_steady_clock_core; | ||
| 203 | Clock::TickBasedSteadyClockCore tick_based_steady_clock_core; | ||
| 204 | Clock::StandardLocalSystemClockCore standard_local_system_clock_core; | ||
| 205 | Clock::StandardNetworkSystemClockCore standard_network_system_clock_core; | ||
| 206 | Clock::StandardUserSystemClockCore standard_user_system_clock_core; | ||
| 207 | Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core; | ||
| 208 | |||
| 209 | std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer; | ||
| 210 | std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer; | ||
| 211 | std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter> | ||
| 212 | ephemeral_network_system_clock_context_writer; | ||
| 213 | |||
| 214 | TimeZone::TimeZoneContentManager time_zone_content_manager; | ||
| 215 | }; | ||
| 216 | |||
| 217 | TimeManager::TimeManager(Core::System& system_) : system{system_} {} | ||
| 218 | |||
| 219 | TimeManager::~TimeManager() = default; | ||
| 220 | |||
| 221 | void TimeManager::Initialize() { | ||
| 222 | impl = std::make_unique<Impl>(system); | ||
| 223 | |||
| 224 | // Time zones can only be initialized after impl is valid | ||
| 225 | impl->time_zone_content_manager.Initialize(*this); | ||
| 226 | } | ||
| 227 | |||
| 228 | Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() { | ||
| 229 | return impl->standard_steady_clock_core; | ||
| 230 | } | ||
| 231 | |||
| 232 | const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const { | ||
| 233 | return impl->standard_steady_clock_core; | ||
| 234 | } | ||
| 235 | |||
| 236 | Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() { | ||
| 237 | return impl->standard_local_system_clock_core; | ||
| 238 | } | ||
| 239 | |||
| 240 | const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const { | ||
| 241 | return impl->standard_local_system_clock_core; | ||
| 242 | } | ||
| 243 | |||
| 244 | Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() { | ||
| 245 | return impl->standard_network_system_clock_core; | ||
| 246 | } | ||
| 247 | |||
| 248 | const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() | ||
| 249 | const { | ||
| 250 | return impl->standard_network_system_clock_core; | ||
| 251 | } | ||
| 252 | |||
| 253 | Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() { | ||
| 254 | return impl->standard_user_system_clock_core; | ||
| 255 | } | ||
| 256 | |||
| 257 | const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const { | ||
| 258 | return impl->standard_user_system_clock_core; | ||
| 259 | } | ||
| 260 | |||
| 261 | TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() { | ||
| 262 | return impl->time_zone_content_manager; | ||
| 263 | } | ||
| 264 | |||
| 265 | const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const { | ||
| 266 | return impl->time_zone_content_manager; | ||
| 267 | } | ||
| 268 | |||
| 269 | SharedMemory& TimeManager::GetSharedMemory() { | ||
| 270 | return impl->shared_memory; | ||
| 271 | } | ||
| 272 | |||
| 273 | const SharedMemory& TimeManager::GetSharedMemory() const { | ||
| 274 | return impl->shared_memory; | ||
| 275 | } | ||
| 276 | |||
| 277 | void TimeManager::Shutdown() { | ||
| 278 | impl.reset(); | ||
| 279 | } | ||
| 280 | |||
| 281 | void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) { | ||
| 282 | impl->UpdateLocalSystemClockTime(system, posix_time); | ||
| 283 | } | ||
| 284 | |||
| 285 | void TimeManager::SetupTimeZoneManager(std::string location_name, | ||
| 286 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 287 | std::vector<std::string> location_names, | ||
| 288 | u128 time_zone_rule_version, | ||
| 289 | FileSys::VirtualFile& vfs_file) { | ||
| 290 | impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names, | ||
| 291 | time_zone_rule_version, vfs_file); | ||
| 292 | } | ||
| 293 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h deleted file mode 100644 index 84572dbfa..000000000 --- a/src/core/hle/service/time/time_manager.h +++ /dev/null | |||
| @@ -1,74 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/file_sys/vfs_types.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | #include "core/hle/service/time/standard_local_system_clock_core.h" | ||
| 10 | #include "core/hle/service/time/standard_network_system_clock_core.h" | ||
| 11 | #include "core/hle/service/time/standard_steady_clock_core.h" | ||
| 12 | #include "core/hle/service/time/standard_user_system_clock_core.h" | ||
| 13 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 14 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 15 | |||
| 16 | namespace Service::Time { | ||
| 17 | |||
| 18 | namespace Clock { | ||
| 19 | class EphemeralNetworkSystemClockContextWriter; | ||
| 20 | class LocalSystemClockContextWriter; | ||
| 21 | class NetworkSystemClockContextWriter; | ||
| 22 | } // namespace Clock | ||
| 23 | |||
| 24 | // Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). | ||
| 25 | // This code was released under public domain. | ||
| 26 | |||
| 27 | class TimeManager final { | ||
| 28 | public: | ||
| 29 | explicit TimeManager(Core::System& system_); | ||
| 30 | ~TimeManager(); | ||
| 31 | |||
| 32 | void Initialize(); | ||
| 33 | |||
| 34 | Clock::StandardSteadyClockCore& GetStandardSteadyClockCore(); | ||
| 35 | |||
| 36 | const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const; | ||
| 37 | |||
| 38 | Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore(); | ||
| 39 | |||
| 40 | const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const; | ||
| 41 | |||
| 42 | Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore(); | ||
| 43 | |||
| 44 | const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const; | ||
| 45 | |||
| 46 | Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore(); | ||
| 47 | |||
| 48 | const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const; | ||
| 49 | |||
| 50 | TimeZone::TimeZoneContentManager& GetTimeZoneContentManager(); | ||
| 51 | |||
| 52 | const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const; | ||
| 53 | |||
| 54 | void UpdateLocalSystemClockTime(s64 posix_time); | ||
| 55 | |||
| 56 | SharedMemory& GetSharedMemory(); | ||
| 57 | |||
| 58 | const SharedMemory& GetSharedMemory() const; | ||
| 59 | |||
| 60 | void Shutdown(); | ||
| 61 | |||
| 62 | void SetupTimeZoneManager(std::string location_name, | ||
| 63 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 64 | std::vector<std::string> location_names, u128 time_zone_rule_version, | ||
| 65 | FileSys::VirtualFile& vfs_file); | ||
| 66 | |||
| 67 | private: | ||
| 68 | Core::System& system; | ||
| 69 | |||
| 70 | struct Impl; | ||
| 71 | std::unique_ptr<Impl> impl; | ||
| 72 | }; | ||
| 73 | |||
| 74 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp deleted file mode 100644 index a00676669..000000000 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hardware_properties.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 10 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 11 | |||
| 12 | namespace Service::Time { | ||
| 13 | |||
| 14 | static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000}; | ||
| 15 | |||
| 16 | SharedMemory::SharedMemory(Core::System& system_) : system(system_) { | ||
| 17 | std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE); | ||
| 18 | } | ||
| 19 | |||
| 20 | SharedMemory::~SharedMemory() = default; | ||
| 21 | |||
| 22 | void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, | ||
| 23 | Clock::TimeSpanType current_time_point) { | ||
| 24 | const Clock::TimeSpanType ticks_time_span{ | ||
| 25 | Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>( | ||
| 26 | system.CoreTiming().GetClockTicks())}; | ||
| 27 | const Clock::SteadyClockContext context{ | ||
| 28 | static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), | ||
| 29 | clock_source_id}; | ||
| 30 | StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context); | ||
| 31 | } | ||
| 32 | |||
| 33 | void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { | ||
| 34 | // lower and upper are related to the measurement point for the steady time point, | ||
| 35 | // and compare equal on boot | ||
| 36 | const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL; | ||
| 37 | |||
| 38 | // This adjusts for some sort of time skew | ||
| 39 | // Both 0 on boot | ||
| 40 | const s64 diff_scale = 0; | ||
| 41 | const u32 shift_amount = 0; | ||
| 42 | |||
| 43 | const Clock::ContinuousAdjustmentTimePoint adjustment{ | ||
| 44 | .measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(), | ||
| 45 | .diff_scale = diff_scale, | ||
| 46 | .shift_amount = shift_amount, | ||
| 47 | .lower = time_point_ns, | ||
| 48 | .upper = time_point_ns, | ||
| 49 | .clock_source_id = context.steady_time_point.clock_source_id, | ||
| 50 | }; | ||
| 51 | |||
| 52 | StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment); | ||
| 53 | StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context); | ||
| 54 | } | ||
| 55 | |||
| 56 | void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { | ||
| 57 | StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context); | ||
| 58 | } | ||
| 59 | |||
| 60 | void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { | ||
| 61 | StoreToLockFreeAtomicType( | ||
| 62 | &GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled); | ||
| 63 | } | ||
| 64 | |||
| 65 | SharedMemory::Format* SharedMemory::GetFormat() { | ||
| 66 | return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer()); | ||
| 67 | } | ||
| 68 | |||
| 69 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h deleted file mode 100644 index c89be9765..000000000 --- a/src/core/hle/service/time/time_sharedmemory.h +++ /dev/null | |||
| @@ -1,89 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/uuid.h" | ||
| 8 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 9 | #include "core/hle/service/time/clock_types.h" | ||
| 10 | |||
| 11 | namespace Service::Time { | ||
| 12 | |||
| 13 | // Note: this type is not safe for concurrent writes. | ||
| 14 | template <typename T> | ||
| 15 | struct LockFreeAtomicType { | ||
| 16 | u32 counter_; | ||
| 17 | std::array<T, 2> value_; | ||
| 18 | }; | ||
| 19 | |||
| 20 | template <typename T> | ||
| 21 | static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) { | ||
| 22 | // Get the current counter. | ||
| 23 | auto counter = p->counter_; | ||
| 24 | |||
| 25 | // Increment the counter. | ||
| 26 | ++counter; | ||
| 27 | |||
| 28 | // Store the updated value. | ||
| 29 | p->value_[counter % 2] = value; | ||
| 30 | |||
| 31 | // Fence memory. | ||
| 32 | std::atomic_thread_fence(std::memory_order_release); | ||
| 33 | |||
| 34 | // Set the updated counter. | ||
| 35 | p->counter_ = counter; | ||
| 36 | } | ||
| 37 | |||
| 38 | template <typename T> | ||
| 39 | static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) { | ||
| 40 | while (true) { | ||
| 41 | // Get the counter. | ||
| 42 | auto counter = p->counter_; | ||
| 43 | |||
| 44 | // Get the value. | ||
| 45 | auto value = p->value_[counter % 2]; | ||
| 46 | |||
| 47 | // Fence memory. | ||
| 48 | std::atomic_thread_fence(std::memory_order_acquire); | ||
| 49 | |||
| 50 | // Check that the counter matches. | ||
| 51 | if (counter == p->counter_) { | ||
| 52 | return value; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | class SharedMemory final { | ||
| 58 | public: | ||
| 59 | explicit SharedMemory(Core::System& system_); | ||
| 60 | ~SharedMemory(); | ||
| 61 | |||
| 62 | // Shared memory format | ||
| 63 | struct Format { | ||
| 64 | LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint; | ||
| 65 | LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context; | ||
| 66 | LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context; | ||
| 67 | LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled; | ||
| 68 | LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint; | ||
| 69 | }; | ||
| 70 | static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0); | ||
| 71 | static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38); | ||
| 72 | static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80); | ||
| 73 | static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) == | ||
| 74 | 0xc8); | ||
| 75 | static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0); | ||
| 76 | static_assert(sizeof(Format) == 0x148, "Format is an invalid size"); | ||
| 77 | |||
| 78 | void SetupStandardSteadyClock(const Common::UUID& clock_source_id, | ||
| 79 | Clock::TimeSpanType current_time_point); | ||
| 80 | void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); | ||
| 81 | void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); | ||
| 82 | void SetAutomaticCorrectionEnabled(bool is_enabled); | ||
| 83 | Format* GetFormat(); | ||
| 84 | |||
| 85 | private: | ||
| 86 | Core::System& system; | ||
| 87 | }; | ||
| 88 | |||
| 89 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp deleted file mode 100644 index 1b96de37a..000000000 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ /dev/null | |||
| @@ -1,151 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <chrono> | ||
| 5 | #include <sstream> | ||
| 6 | #include <utility> | ||
| 7 | |||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/settings.h" | ||
| 10 | #include "common/time_zone.h" | ||
| 11 | #include "core/core.h" | ||
| 12 | #include "core/file_sys/content_archive.h" | ||
| 13 | #include "core/file_sys/nca_metadata.h" | ||
| 14 | #include "core/file_sys/registered_cache.h" | ||
| 15 | #include "core/file_sys/romfs.h" | ||
| 16 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 17 | #include "core/file_sys/vfs.h" | ||
| 18 | #include "core/file_sys/vfs_types.h" | ||
| 19 | #include "core/hle/result.h" | ||
| 20 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 21 | #include "core/hle/service/time/errors.h" | ||
| 22 | #include "core/hle/service/time/time_manager.h" | ||
| 23 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 24 | |||
| 25 | namespace Service::Time::TimeZone { | ||
| 26 | |||
| 27 | constexpr u64 time_zone_binary_titleid{0x010000000000080E}; | ||
| 28 | |||
| 29 | static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) { | ||
| 30 | const auto* nand{system.GetFileSystemController().GetSystemNANDContents()}; | ||
| 31 | const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)}; | ||
| 32 | |||
| 33 | FileSys::VirtualFile romfs; | ||
| 34 | if (nca) { | ||
| 35 | romfs = nca->GetRomFS(); | ||
| 36 | } | ||
| 37 | |||
| 38 | if (!romfs) { | ||
| 39 | romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid); | ||
| 40 | } | ||
| 41 | |||
| 42 | if (!romfs) { | ||
| 43 | LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid); | ||
| 44 | return {}; | ||
| 45 | } | ||
| 46 | |||
| 47 | return FileSys::ExtractRomFS(romfs); | ||
| 48 | } | ||
| 49 | |||
| 50 | static std::vector<std::string> BuildLocationNameCache( | ||
| 51 | const FileSys::VirtualDir& time_zone_binary) { | ||
| 52 | if (!time_zone_binary) { | ||
| 53 | LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid); | ||
| 54 | return {}; | ||
| 55 | } | ||
| 56 | |||
| 57 | const FileSys::VirtualFile binary_list{time_zone_binary->GetFile("binaryList.txt")}; | ||
| 58 | if (!binary_list) { | ||
| 59 | LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid); | ||
| 60 | return {}; | ||
| 61 | } | ||
| 62 | |||
| 63 | std::vector<char> raw_data(binary_list->GetSize() + 1); | ||
| 64 | binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize()); | ||
| 65 | |||
| 66 | std::stringstream data_stream{raw_data.data()}; | ||
| 67 | std::string name; | ||
| 68 | std::vector<std::string> location_name_cache; | ||
| 69 | while (std::getline(data_stream, name)) { | ||
| 70 | name.pop_back(); // Remove carriage return | ||
| 71 | location_name_cache.emplace_back(std::move(name)); | ||
| 72 | } | ||
| 73 | return location_name_cache; | ||
| 74 | } | ||
| 75 | |||
| 76 | TimeZoneContentManager::TimeZoneContentManager(Core::System& system_) | ||
| 77 | : system{system_}, time_zone_binary{GetTimeZoneBinary(system)}, | ||
| 78 | location_name_cache{BuildLocationNameCache(time_zone_binary)} {} | ||
| 79 | |||
| 80 | void TimeZoneContentManager::Initialize(TimeManager& time_manager) { | ||
| 81 | const auto timezone_setting = | ||
| 82 | Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); | ||
| 83 | |||
| 84 | if (FileSys::VirtualFile vfs_file; | ||
| 85 | GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) { | ||
| 86 | const auto time_point{ | ||
| 87 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; | ||
| 88 | time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {}, | ||
| 89 | vfs_file); | ||
| 90 | } else { | ||
| 91 | time_zone_manager.MarkAsInitialized(); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | Result TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules, | ||
| 96 | const std::string& location_name) const { | ||
| 97 | FileSys::VirtualFile vfs_file; | ||
| 98 | if (const Result result{GetTimeZoneInfoFile(location_name, vfs_file)}; | ||
| 99 | result != ResultSuccess) { | ||
| 100 | return result; | ||
| 101 | } | ||
| 102 | |||
| 103 | return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file); | ||
| 104 | } | ||
| 105 | |||
| 106 | bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const { | ||
| 107 | return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) != | ||
| 108 | location_name_cache.end(); | ||
| 109 | } | ||
| 110 | |||
| 111 | Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name, | ||
| 112 | FileSys::VirtualFile& vfs_file) const { | ||
| 113 | if (!IsLocationNameValid(location_name)) { | ||
| 114 | return ERROR_TIME_NOT_FOUND; | ||
| 115 | } | ||
| 116 | |||
| 117 | if (!time_zone_binary) { | ||
| 118 | LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid); | ||
| 119 | return ERROR_TIME_NOT_FOUND; | ||
| 120 | } | ||
| 121 | |||
| 122 | const FileSys::VirtualDir zoneinfo_dir{time_zone_binary->GetSubdirectory("zoneinfo")}; | ||
| 123 | if (!zoneinfo_dir) { | ||
| 124 | LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid); | ||
| 125 | return ERROR_TIME_NOT_FOUND; | ||
| 126 | } | ||
| 127 | |||
| 128 | vfs_file = zoneinfo_dir->GetFileRelative(location_name); | ||
| 129 | if (!vfs_file) { | ||
| 130 | LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.", | ||
| 131 | time_zone_binary_titleid, location_name); | ||
| 132 | const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()}; | ||
| 133 | vfs_file = zoneinfo_dir->GetFile(system_time_zone); | ||
| 134 | } | ||
| 135 | |||
| 136 | if (!vfs_file) { | ||
| 137 | LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", | ||
| 138 | time_zone_binary_titleid, location_name); | ||
| 139 | vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); | ||
| 140 | } | ||
| 141 | |||
| 142 | if (!vfs_file) { | ||
| 143 | LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid, | ||
| 144 | location_name); | ||
| 145 | return ERROR_TIME_NOT_FOUND; | ||
| 146 | } | ||
| 147 | |||
| 148 | return ResultSuccess; | ||
| 149 | } | ||
| 150 | |||
| 151 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h deleted file mode 100644 index a6f9698bc..000000000 --- a/src/core/hle/service/time/time_zone_content_manager.h +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <string> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "core/file_sys/vfs_types.h" | ||
| 10 | #include "core/hle/service/time/time_zone_manager.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Time { | ||
| 17 | class TimeManager; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::Time::TimeZone { | ||
| 21 | |||
| 22 | class TimeZoneContentManager final { | ||
| 23 | public: | ||
| 24 | explicit TimeZoneContentManager(Core::System& system_); | ||
| 25 | |||
| 26 | void Initialize(TimeManager& time_manager); | ||
| 27 | |||
| 28 | TimeZoneManager& GetTimeZoneManager() { | ||
| 29 | return time_zone_manager; | ||
| 30 | } | ||
| 31 | |||
| 32 | const TimeZoneManager& GetTimeZoneManager() const { | ||
| 33 | return time_zone_manager; | ||
| 34 | } | ||
| 35 | |||
| 36 | Result LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const; | ||
| 37 | |||
| 38 | private: | ||
| 39 | bool IsLocationNameValid(const std::string& location_name) const; | ||
| 40 | Result GetTimeZoneInfoFile(const std::string& location_name, | ||
| 41 | FileSys::VirtualFile& vfs_file) const; | ||
| 42 | |||
| 43 | Core::System& system; | ||
| 44 | TimeZoneManager time_zone_manager; | ||
| 45 | const FileSys::VirtualDir time_zone_binary; | ||
| 46 | const std::vector<std::string> location_name_cache; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp deleted file mode 100644 index 205371a26..000000000 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ /dev/null | |||
| @@ -1,1182 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <climits> | ||
| 5 | #include <limits> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/file_sys/content_archive.h" | ||
| 10 | #include "core/file_sys/nca_metadata.h" | ||
| 11 | #include "core/file_sys/registered_cache.h" | ||
| 12 | #include "core/hle/service/time/time_zone_manager.h" | ||
| 13 | #include "core/hle/service/time/time_zone_types.h" | ||
| 14 | |||
| 15 | namespace Service::Time::TimeZone { | ||
| 16 | |||
| 17 | static constexpr s32 epoch_year{1970}; | ||
| 18 | static constexpr s32 year_base{1900}; | ||
| 19 | static constexpr s32 epoch_week_day{4}; | ||
| 20 | static constexpr s32 seconds_per_minute{60}; | ||
| 21 | static constexpr s32 minutes_per_hour{60}; | ||
| 22 | static constexpr s32 hours_per_day{24}; | ||
| 23 | static constexpr s32 days_per_week{7}; | ||
| 24 | static constexpr s32 days_per_normal_year{365}; | ||
| 25 | static constexpr s32 days_per_leap_year{366}; | ||
| 26 | static constexpr s32 months_per_year{12}; | ||
| 27 | static constexpr s32 seconds_per_hour{seconds_per_minute * minutes_per_hour}; | ||
| 28 | static constexpr s32 seconds_per_day{seconds_per_hour * hours_per_day}; | ||
| 29 | static constexpr s32 years_per_repeat{400}; | ||
| 30 | static constexpr s64 average_seconds_per_year{31556952}; | ||
| 31 | static constexpr s64 seconds_per_repeat{years_per_repeat * average_seconds_per_year}; | ||
| 32 | |||
| 33 | struct Rule { | ||
| 34 | enum class Type : u32 { JulianDay, DayOfYear, MonthNthDayOfWeek }; | ||
| 35 | Type rule_type{}; | ||
| 36 | s32 day{}; | ||
| 37 | s32 week{}; | ||
| 38 | s32 month{}; | ||
| 39 | s32 transition_time{}; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct CalendarTimeInternal { | ||
| 43 | s64 year{}; | ||
| 44 | s8 month{}; | ||
| 45 | s8 day{}; | ||
| 46 | s8 hour{}; | ||
| 47 | s8 minute{}; | ||
| 48 | s8 second{}; | ||
| 49 | int Compare(const CalendarTimeInternal& other) const { | ||
| 50 | if (year != other.year) { | ||
| 51 | if (year < other.year) { | ||
| 52 | return -1; | ||
| 53 | } | ||
| 54 | return 1; | ||
| 55 | } | ||
| 56 | if (month != other.month) { | ||
| 57 | return month - other.month; | ||
| 58 | } | ||
| 59 | if (day != other.day) { | ||
| 60 | return day - other.day; | ||
| 61 | } | ||
| 62 | if (hour != other.hour) { | ||
| 63 | return hour - other.hour; | ||
| 64 | } | ||
| 65 | if (minute != other.minute) { | ||
| 66 | return minute - other.minute; | ||
| 67 | } | ||
| 68 | if (second != other.second) { | ||
| 69 | return second - other.second; | ||
| 70 | } | ||
| 71 | return {}; | ||
| 72 | } | ||
| 73 | }; | ||
| 74 | |||
| 75 | template <typename TResult, typename TOperand> | ||
| 76 | static bool SafeAdd(TResult& result, TOperand op) { | ||
| 77 | result = result + op; | ||
| 78 | return true; | ||
| 79 | } | ||
| 80 | |||
| 81 | template <typename TResult, typename TUnit, typename TBase> | ||
| 82 | static bool SafeNormalize(TResult& result, TUnit& unit, TBase base) { | ||
| 83 | TUnit delta{}; | ||
| 84 | if (unit >= 0) { | ||
| 85 | delta = unit / base; | ||
| 86 | } else { | ||
| 87 | delta = -1 - (-1 - unit) / base; | ||
| 88 | } | ||
| 89 | unit -= delta * base; | ||
| 90 | return SafeAdd(result, delta); | ||
| 91 | } | ||
| 92 | |||
| 93 | template <typename T> | ||
| 94 | static constexpr bool IsLeapYear(T year) { | ||
| 95 | return ((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0); | ||
| 96 | } | ||
| 97 | |||
| 98 | template <typename T> | ||
| 99 | static constexpr T GetYearLengthInDays(T year) { | ||
| 100 | return IsLeapYear(year) ? days_per_leap_year : days_per_normal_year; | ||
| 101 | } | ||
| 102 | |||
| 103 | static constexpr s64 GetLeapDaysFromYearPositive(s64 year) { | ||
| 104 | return year / 4 - year / 100 + year / years_per_repeat; | ||
| 105 | } | ||
| 106 | |||
| 107 | static constexpr s64 GetLeapDaysFromYear(s64 year) { | ||
| 108 | if (year < 0) { | ||
| 109 | return -1 - GetLeapDaysFromYearPositive(-1 - year); | ||
| 110 | } else { | ||
| 111 | return GetLeapDaysFromYearPositive(year); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | static constexpr s8 GetMonthLength(bool is_leap_year, int month) { | ||
| 116 | constexpr std::array<s8, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
| 117 | constexpr std::array<s8, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
| 118 | return is_leap_year ? month_lengths_leap[month] : month_lengths[month]; | ||
| 119 | } | ||
| 120 | |||
| 121 | static constexpr bool IsDigit(char value) { | ||
| 122 | return value >= '0' && value <= '9'; | ||
| 123 | } | ||
| 124 | |||
| 125 | static constexpr int GetQZName(const char* name, int offset, char delimiter) { | ||
| 126 | while (name[offset] != '\0' && name[offset] != delimiter) { | ||
| 127 | offset++; | ||
| 128 | } | ||
| 129 | return offset; | ||
| 130 | } | ||
| 131 | |||
| 132 | static constexpr int GetTZName(const char* name, int offset) { | ||
| 133 | char c; | ||
| 134 | |||
| 135 | while ((c = name[offset]) != '\0' && !IsDigit(c) && c != ',' && c != '-' && c != '+') { | ||
| 136 | ++offset; | ||
| 137 | } | ||
| 138 | return offset; | ||
| 139 | } | ||
| 140 | |||
| 141 | static constexpr bool GetInteger(const char* name, int& offset, int& value, int min, int max) { | ||
| 142 | value = 0; | ||
| 143 | char temp{name[offset]}; | ||
| 144 | if (!IsDigit(temp)) { | ||
| 145 | return {}; | ||
| 146 | } | ||
| 147 | do { | ||
| 148 | value = value * 10 + (temp - '0'); | ||
| 149 | if (value > max) { | ||
| 150 | return {}; | ||
| 151 | } | ||
| 152 | offset++; | ||
| 153 | temp = name[offset]; | ||
| 154 | } while (IsDigit(temp)); | ||
| 155 | |||
| 156 | return value >= min; | ||
| 157 | } | ||
| 158 | |||
| 159 | static constexpr bool GetSeconds(const char* name, int& offset, int& seconds) { | ||
| 160 | seconds = 0; | ||
| 161 | int value{}; | ||
| 162 | if (!GetInteger(name, offset, value, 0, hours_per_day * days_per_week - 1)) { | ||
| 163 | return {}; | ||
| 164 | } | ||
| 165 | seconds = value * seconds_per_hour; | ||
| 166 | |||
| 167 | if (name[offset] == ':') { | ||
| 168 | offset++; | ||
| 169 | if (!GetInteger(name, offset, value, 0, minutes_per_hour - 1)) { | ||
| 170 | return {}; | ||
| 171 | } | ||
| 172 | seconds += value * seconds_per_minute; | ||
| 173 | if (name[offset] == ':') { | ||
| 174 | offset++; | ||
| 175 | if (!GetInteger(name, offset, value, 0, seconds_per_minute)) { | ||
| 176 | return {}; | ||
| 177 | } | ||
| 178 | seconds += value; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | return true; | ||
| 182 | } | ||
| 183 | |||
| 184 | static constexpr bool GetOffset(const char* name, int& offset, int& value) { | ||
| 185 | bool is_negative{}; | ||
| 186 | if (name[offset] == '-') { | ||
| 187 | is_negative = true; | ||
| 188 | offset++; | ||
| 189 | } else if (name[offset] == '+') { | ||
| 190 | offset++; | ||
| 191 | } | ||
| 192 | if (!GetSeconds(name, offset, value)) { | ||
| 193 | return {}; | ||
| 194 | } | ||
| 195 | if (is_negative) { | ||
| 196 | value = -value; | ||
| 197 | } | ||
| 198 | return true; | ||
| 199 | } | ||
| 200 | |||
| 201 | static constexpr bool GetRule(const char* name, int& position, Rule& rule) { | ||
| 202 | bool is_valid{}; | ||
| 203 | if (name[position] == 'J') { | ||
| 204 | position++; | ||
| 205 | rule.rule_type = Rule::Type::JulianDay; | ||
| 206 | is_valid = GetInteger(name, position, rule.day, 1, days_per_normal_year); | ||
| 207 | } else if (name[position] == 'M') { | ||
| 208 | position++; | ||
| 209 | rule.rule_type = Rule::Type::MonthNthDayOfWeek; | ||
| 210 | is_valid = GetInteger(name, position, rule.month, 1, months_per_year); | ||
| 211 | if (!is_valid) { | ||
| 212 | return {}; | ||
| 213 | } | ||
| 214 | if (name[position++] != '.') { | ||
| 215 | return {}; | ||
| 216 | } | ||
| 217 | is_valid = GetInteger(name, position, rule.week, 1, 5); | ||
| 218 | if (!is_valid) { | ||
| 219 | return {}; | ||
| 220 | } | ||
| 221 | if (name[position++] != '.') { | ||
| 222 | return {}; | ||
| 223 | } | ||
| 224 | is_valid = GetInteger(name, position, rule.day, 0, days_per_week - 1); | ||
| 225 | } else if (isdigit(name[position])) { | ||
| 226 | rule.rule_type = Rule::Type::DayOfYear; | ||
| 227 | is_valid = GetInteger(name, position, rule.day, 0, days_per_leap_year - 1); | ||
| 228 | } else { | ||
| 229 | return {}; | ||
| 230 | } | ||
| 231 | if (!is_valid) { | ||
| 232 | return {}; | ||
| 233 | } | ||
| 234 | if (name[position] == '/') { | ||
| 235 | position++; | ||
| 236 | return GetOffset(name, position, rule.transition_time); | ||
| 237 | } else { | ||
| 238 | rule.transition_time = 2 * seconds_per_hour; | ||
| 239 | } | ||
| 240 | return true; | ||
| 241 | } | ||
| 242 | |||
| 243 | static constexpr int TransitionTime(int year, Rule rule, int offset) { | ||
| 244 | int value{}; | ||
| 245 | switch (rule.rule_type) { | ||
| 246 | case Rule::Type::JulianDay: | ||
| 247 | value = (rule.day - 1) * seconds_per_day; | ||
| 248 | if (IsLeapYear(year) && rule.day >= 60) { | ||
| 249 | value += seconds_per_day; | ||
| 250 | } | ||
| 251 | break; | ||
| 252 | case Rule::Type::DayOfYear: | ||
| 253 | value = rule.day * seconds_per_day; | ||
| 254 | break; | ||
| 255 | case Rule::Type::MonthNthDayOfWeek: { | ||
| 256 | // Use Zeller's Congruence (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to | ||
| 257 | // calculate the day of the week for any Julian or Gregorian calendar date. | ||
| 258 | const int m1{(rule.month + 9) % 12 + 1}; | ||
| 259 | const int yy0{(rule.month <= 2) ? (year - 1) : year}; | ||
| 260 | const int yy1{yy0 / 100}; | ||
| 261 | const int yy2{yy0 % 100}; | ||
| 262 | int day_of_week{((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7}; | ||
| 263 | |||
| 264 | if (day_of_week < 0) { | ||
| 265 | day_of_week += days_per_week; | ||
| 266 | } | ||
| 267 | int day{rule.day - day_of_week}; | ||
| 268 | if (day < 0) { | ||
| 269 | day += days_per_week; | ||
| 270 | } | ||
| 271 | for (int i{1}; i < rule.week; i++) { | ||
| 272 | if (day + days_per_week >= GetMonthLength(IsLeapYear(year), rule.month - 1)) { | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | day += days_per_week; | ||
| 276 | } | ||
| 277 | |||
| 278 | value = day * seconds_per_day; | ||
| 279 | for (int index{}; index < rule.month - 1; ++index) { | ||
| 280 | value += GetMonthLength(IsLeapYear(year), index) * seconds_per_day; | ||
| 281 | } | ||
| 282 | break; | ||
| 283 | } | ||
| 284 | default: | ||
| 285 | ASSERT(false); | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | return value + rule.transition_time + offset; | ||
| 289 | } | ||
| 290 | |||
| 291 | static bool ParsePosixName(const char* name, TimeZoneRule& rule) { | ||
| 292 | static constexpr char default_rule[]{",M4.1.0,M10.5.0"}; | ||
| 293 | const char* std_name{name}; | ||
| 294 | int std_len{}; | ||
| 295 | int offset{}; | ||
| 296 | int std_offset{}; | ||
| 297 | |||
| 298 | if (name[offset] == '<') { | ||
| 299 | offset++; | ||
| 300 | std_name = name + offset; | ||
| 301 | const int std_name_offset{offset}; | ||
| 302 | offset = GetQZName(name, offset, '>'); | ||
| 303 | if (name[offset] != '>') { | ||
| 304 | return {}; | ||
| 305 | } | ||
| 306 | std_len = offset - std_name_offset; | ||
| 307 | offset++; | ||
| 308 | } else { | ||
| 309 | offset = GetTZName(name, offset); | ||
| 310 | std_len = offset; | ||
| 311 | } | ||
| 312 | if (std_len == 0) { | ||
| 313 | return {}; | ||
| 314 | } | ||
| 315 | if (!GetOffset(name, offset, std_offset)) { | ||
| 316 | return {}; | ||
| 317 | } | ||
| 318 | |||
| 319 | int char_count{std_len + 1}; | ||
| 320 | int dest_len{}; | ||
| 321 | int dest_offset{}; | ||
| 322 | const char* dest_name{name + offset}; | ||
| 323 | if (rule.chars.size() < std::size_t(char_count)) { | ||
| 324 | return {}; | ||
| 325 | } | ||
| 326 | |||
| 327 | if (name[offset] != '\0') { | ||
| 328 | if (name[offset] == '<') { | ||
| 329 | dest_name = name + (++offset); | ||
| 330 | const int dest_name_offset{offset}; | ||
| 331 | offset = GetQZName(name, offset, '>'); | ||
| 332 | if (name[offset] != '>') { | ||
| 333 | return {}; | ||
| 334 | } | ||
| 335 | dest_len = offset - dest_name_offset; | ||
| 336 | offset++; | ||
| 337 | } else { | ||
| 338 | dest_name = name + (offset); | ||
| 339 | offset = GetTZName(name, offset); | ||
| 340 | dest_len = offset; | ||
| 341 | } | ||
| 342 | if (dest_len == 0) { | ||
| 343 | return {}; | ||
| 344 | } | ||
| 345 | char_count += dest_len + 1; | ||
| 346 | if (rule.chars.size() < std::size_t(char_count)) { | ||
| 347 | return {}; | ||
| 348 | } | ||
| 349 | if (name[offset] != '\0' && name[offset] != ',' && name[offset] != ';') { | ||
| 350 | if (!GetOffset(name, offset, dest_offset)) { | ||
| 351 | return {}; | ||
| 352 | } | ||
| 353 | } else { | ||
| 354 | dest_offset = std_offset - seconds_per_hour; | ||
| 355 | } | ||
| 356 | if (name[offset] == '\0') { | ||
| 357 | name = default_rule; | ||
| 358 | offset = 0; | ||
| 359 | } | ||
| 360 | if (name[offset] == ',' || name[offset] == ';') { | ||
| 361 | offset++; | ||
| 362 | |||
| 363 | Rule start{}; | ||
| 364 | if (!GetRule(name, offset, start)) { | ||
| 365 | return {}; | ||
| 366 | } | ||
| 367 | if (name[offset++] != ',') { | ||
| 368 | return {}; | ||
| 369 | } | ||
| 370 | |||
| 371 | Rule end{}; | ||
| 372 | if (!GetRule(name, offset, end)) { | ||
| 373 | return {}; | ||
| 374 | } | ||
| 375 | if (name[offset] != '\0') { | ||
| 376 | return {}; | ||
| 377 | } | ||
| 378 | |||
| 379 | rule.type_count = 2; | ||
| 380 | rule.ttis[0].gmt_offset = -dest_offset; | ||
| 381 | rule.ttis[0].is_dst = true; | ||
| 382 | rule.ttis[0].abbreviation_list_index = std_len + 1; | ||
| 383 | rule.ttis[1].gmt_offset = -std_offset; | ||
| 384 | rule.ttis[1].is_dst = false; | ||
| 385 | rule.ttis[1].abbreviation_list_index = 0; | ||
| 386 | rule.default_type = 0; | ||
| 387 | |||
| 388 | s64 jan_first{}; | ||
| 389 | int time_count{}; | ||
| 390 | int jan_offset{}; | ||
| 391 | int year_beginning{epoch_year}; | ||
| 392 | do { | ||
| 393 | const int year_seconds{GetYearLengthInDays(year_beginning - 1) * seconds_per_day}; | ||
| 394 | year_beginning--; | ||
| 395 | if (!SafeAdd(jan_first, -year_seconds)) { | ||
| 396 | jan_offset = -year_seconds; | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | } while (epoch_year - years_per_repeat / 2 < year_beginning); | ||
| 400 | |||
| 401 | int year_limit{year_beginning + years_per_repeat + 1}; | ||
| 402 | int year{}; | ||
| 403 | for (year = year_beginning; year < year_limit; year++) { | ||
| 404 | int start_time{TransitionTime(year, start, std_offset)}; | ||
| 405 | int end_time{TransitionTime(year, end, dest_offset)}; | ||
| 406 | const int year_seconds{GetYearLengthInDays(year) * seconds_per_day}; | ||
| 407 | const bool is_reversed{end_time < start_time}; | ||
| 408 | if (is_reversed) { | ||
| 409 | int swap{start_time}; | ||
| 410 | start_time = end_time; | ||
| 411 | end_time = swap; | ||
| 412 | } | ||
| 413 | |||
| 414 | if (is_reversed || | ||
| 415 | (start_time < end_time && | ||
| 416 | (end_time - start_time < (year_seconds + (std_offset - dest_offset))))) { | ||
| 417 | if (rule.ats.size() - 2 < std::size_t(time_count)) { | ||
| 418 | break; | ||
| 419 | } | ||
| 420 | |||
| 421 | rule.ats[time_count] = jan_first; | ||
| 422 | if (SafeAdd(rule.ats[time_count], jan_offset + start_time)) { | ||
| 423 | rule.types[time_count++] = is_reversed ? 1 : 0; | ||
| 424 | } else if (jan_offset != 0) { | ||
| 425 | rule.default_type = is_reversed ? 1 : 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | rule.ats[time_count] = jan_first; | ||
| 429 | if (SafeAdd(rule.ats[time_count], jan_offset + end_time)) { | ||
| 430 | rule.types[time_count++] = is_reversed ? 0 : 1; | ||
| 431 | year_limit = year + years_per_repeat + 1; | ||
| 432 | } else if (jan_offset != 0) { | ||
| 433 | rule.default_type = is_reversed ? 0 : 1; | ||
| 434 | } | ||
| 435 | } | ||
| 436 | if (!SafeAdd(jan_first, jan_offset + year_seconds)) { | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | jan_offset = 0; | ||
| 440 | } | ||
| 441 | rule.time_count = time_count; | ||
| 442 | if (time_count == 0) { | ||
| 443 | rule.type_count = 1; | ||
| 444 | } else if (years_per_repeat < year - year_beginning) { | ||
| 445 | rule.go_back = true; | ||
| 446 | rule.go_ahead = true; | ||
| 447 | } | ||
| 448 | } else { | ||
| 449 | if (name[offset] == '\0') { | ||
| 450 | return {}; | ||
| 451 | } | ||
| 452 | |||
| 453 | s64 their_std_offset{}; | ||
| 454 | for (int index{}; index < rule.time_count; ++index) { | ||
| 455 | const s8 type{rule.types[index]}; | ||
| 456 | if (rule.ttis[type].is_standard_time_daylight) { | ||
| 457 | their_std_offset = -rule.ttis[type].gmt_offset; | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | s64 their_offset{their_std_offset}; | ||
| 462 | for (int index{}; index < rule.time_count; ++index) { | ||
| 463 | const s8 type{rule.types[index]}; | ||
| 464 | rule.types[index] = rule.ttis[type].is_dst ? 1 : 0; | ||
| 465 | if (!rule.ttis[type].is_gmt) { | ||
| 466 | if (!rule.ttis[type].is_standard_time_daylight) { | ||
| 467 | rule.ats[index] += dest_offset - their_std_offset; | ||
| 468 | } else { | ||
| 469 | rule.ats[index] += std_offset - their_std_offset; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | their_offset = -rule.ttis[type].gmt_offset; | ||
| 473 | if (!rule.ttis[type].is_dst) { | ||
| 474 | their_std_offset = their_offset; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | |||
| 478 | if (rule.time_count > 0) { | ||
| 479 | UNIMPLEMENTED(); | ||
| 480 | // TODO (lat9nq): Implement eggert/tz/localtime.c:tzparse:1329 | ||
| 481 | // Seems to be unused in yuzu for now: I never hit the UNIMPLEMENTED in testing | ||
| 482 | } | ||
| 483 | |||
| 484 | rule.ttis[0].gmt_offset = -std_offset; | ||
| 485 | rule.ttis[0].is_dst = false; | ||
| 486 | rule.ttis[0].abbreviation_list_index = 0; | ||
| 487 | rule.ttis[1].gmt_offset = -dest_offset; | ||
| 488 | rule.ttis[1].is_dst = true; | ||
| 489 | rule.ttis[1].abbreviation_list_index = std_len + 1; | ||
| 490 | rule.type_count = 2; | ||
| 491 | rule.default_type = 0; | ||
| 492 | } | ||
| 493 | } else { | ||
| 494 | // Default is standard time | ||
| 495 | rule.type_count = 1; | ||
| 496 | rule.time_count = 0; | ||
| 497 | rule.default_type = 0; | ||
| 498 | rule.ttis[0].gmt_offset = -std_offset; | ||
| 499 | rule.ttis[0].is_dst = false; | ||
| 500 | rule.ttis[0].abbreviation_list_index = 0; | ||
| 501 | } | ||
| 502 | |||
| 503 | rule.char_count = char_count; | ||
| 504 | for (int index{}; index < std_len; ++index) { | ||
| 505 | rule.chars[index] = std_name[index]; | ||
| 506 | } | ||
| 507 | |||
| 508 | rule.chars[std_len++] = '\0'; | ||
| 509 | if (dest_len != 0) { | ||
| 510 | for (int index{}; index < dest_len; ++index) { | ||
| 511 | rule.chars[std_len + index] = dest_name[index]; | ||
| 512 | } | ||
| 513 | rule.chars[std_len + dest_len] = '\0'; | ||
| 514 | } | ||
| 515 | |||
| 516 | return true; | ||
| 517 | } | ||
| 518 | |||
| 519 | static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFile& vfs_file) { | ||
| 520 | TzifHeader header{}; | ||
| 521 | if (vfs_file->ReadObject<TzifHeader>(&header) != sizeof(TzifHeader)) { | ||
| 522 | return {}; | ||
| 523 | } | ||
| 524 | |||
| 525 | constexpr s32 time_zone_max_leaps{50}; | ||
| 526 | constexpr s32 time_zone_max_chars{50}; | ||
| 527 | constexpr s32 time_zone_max_times{1000}; | ||
| 528 | if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps && | ||
| 529 | 0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) && | ||
| 530 | 0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) && | ||
| 531 | 0 <= header.char_count && header.char_count < time_zone_max_chars && | ||
| 532 | (header.ttis_std_count == header.type_count || header.ttis_std_count == 0) && | ||
| 533 | (header.ttis_gmt_count == header.type_count || header.ttis_gmt_count == 0))) { | ||
| 534 | return {}; | ||
| 535 | } | ||
| 536 | time_zone_rule.time_count = header.time_count; | ||
| 537 | time_zone_rule.type_count = header.type_count; | ||
| 538 | time_zone_rule.char_count = header.char_count; | ||
| 539 | |||
| 540 | int time_count{}; | ||
| 541 | u64 read_offset = sizeof(TzifHeader); | ||
| 542 | for (int index{}; index < time_zone_rule.time_count; ++index) { | ||
| 543 | s64_be at{}; | ||
| 544 | vfs_file->ReadObject<s64_be>(&at, read_offset); | ||
| 545 | time_zone_rule.types[index] = 1; | ||
| 546 | if (time_count != 0 && at <= time_zone_rule.ats[time_count - 1]) { | ||
| 547 | if (at < time_zone_rule.ats[time_count - 1]) { | ||
| 548 | return {}; | ||
| 549 | } | ||
| 550 | time_zone_rule.types[index - 1] = 0; | ||
| 551 | time_count--; | ||
| 552 | } | ||
| 553 | time_zone_rule.ats[time_count++] = at; | ||
| 554 | read_offset += sizeof(s64_be); | ||
| 555 | } | ||
| 556 | time_count = 0; | ||
| 557 | for (int index{}; index < time_zone_rule.time_count; ++index) { | ||
| 558 | const u8 type{*vfs_file->ReadByte(read_offset)}; | ||
| 559 | read_offset += sizeof(u8); | ||
| 560 | if (time_zone_rule.type_count <= type) { | ||
| 561 | return {}; | ||
| 562 | } | ||
| 563 | if (time_zone_rule.types[index] != 0) { | ||
| 564 | time_zone_rule.types[time_count++] = type; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | time_zone_rule.time_count = time_count; | ||
| 568 | for (int index{}; index < time_zone_rule.type_count; ++index) { | ||
| 569 | TimeTypeInfo& ttis{time_zone_rule.ttis[index]}; | ||
| 570 | u32_be gmt_offset{}; | ||
| 571 | vfs_file->ReadObject<u32_be>(&gmt_offset, read_offset); | ||
| 572 | read_offset += sizeof(u32_be); | ||
| 573 | ttis.gmt_offset = gmt_offset; | ||
| 574 | |||
| 575 | const u8 dst{*vfs_file->ReadByte(read_offset)}; | ||
| 576 | read_offset += sizeof(u8); | ||
| 577 | if (dst >= 2) { | ||
| 578 | return {}; | ||
| 579 | } | ||
| 580 | ttis.is_dst = dst != 0; | ||
| 581 | |||
| 582 | const s32 abbreviation_list_index{*vfs_file->ReadByte(read_offset)}; | ||
| 583 | read_offset += sizeof(u8); | ||
| 584 | if (abbreviation_list_index >= time_zone_rule.char_count) { | ||
| 585 | return {}; | ||
| 586 | } | ||
| 587 | ttis.abbreviation_list_index = abbreviation_list_index; | ||
| 588 | } | ||
| 589 | |||
| 590 | vfs_file->ReadArray(time_zone_rule.chars.data(), time_zone_rule.char_count, read_offset); | ||
| 591 | time_zone_rule.chars[time_zone_rule.char_count] = '\0'; | ||
| 592 | read_offset += time_zone_rule.char_count; | ||
| 593 | for (int index{}; index < time_zone_rule.type_count; ++index) { | ||
| 594 | if (header.ttis_std_count == 0) { | ||
| 595 | time_zone_rule.ttis[index].is_standard_time_daylight = false; | ||
| 596 | } else { | ||
| 597 | const u8 dst{*vfs_file->ReadByte(read_offset)}; | ||
| 598 | read_offset += sizeof(u8); | ||
| 599 | if (dst >= 2) { | ||
| 600 | return {}; | ||
| 601 | } | ||
| 602 | time_zone_rule.ttis[index].is_standard_time_daylight = dst != 0; | ||
| 603 | } | ||
| 604 | } | ||
| 605 | |||
| 606 | for (int index{}; index < time_zone_rule.type_count; ++index) { | ||
| 607 | if (header.ttis_std_count == 0) { | ||
| 608 | time_zone_rule.ttis[index].is_gmt = false; | ||
| 609 | } else { | ||
| 610 | const u8 dst{*vfs_file->ReadByte(read_offset)}; | ||
| 611 | read_offset += sizeof(u8); | ||
| 612 | if (dst >= 2) { | ||
| 613 | return {}; | ||
| 614 | } | ||
| 615 | time_zone_rule.ttis[index].is_gmt = dst != 0; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | |||
| 619 | const u64 position{(read_offset - sizeof(TzifHeader))}; | ||
| 620 | const s64 bytes_read = s64(vfs_file->GetSize() - sizeof(TzifHeader) - position); | ||
| 621 | if (bytes_read < 0) { | ||
| 622 | return {}; | ||
| 623 | } | ||
| 624 | constexpr s32 time_zone_name_max{255}; | ||
| 625 | if (bytes_read > (time_zone_name_max + 1)) { | ||
| 626 | return {}; | ||
| 627 | } | ||
| 628 | |||
| 629 | std::array<char, time_zone_name_max + 1> temp_name{}; | ||
| 630 | vfs_file->ReadArray(temp_name.data(), bytes_read, read_offset); | ||
| 631 | if (bytes_read > 2 && temp_name[0] == '\n' && temp_name[bytes_read - 1] == '\n' && | ||
| 632 | std::size_t(time_zone_rule.type_count) + 2 <= time_zone_rule.ttis.size()) { | ||
| 633 | temp_name[bytes_read - 1] = '\0'; | ||
| 634 | |||
| 635 | std::array<char, time_zone_name_max> name{}; | ||
| 636 | std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1)); | ||
| 637 | |||
| 638 | // Fill in computed transition times with temp rule | ||
| 639 | TimeZoneRule temp_rule; | ||
| 640 | if (ParsePosixName(name.data(), temp_rule)) { | ||
| 641 | int have_abbreviation = 0; | ||
| 642 | int char_count = time_zone_rule.char_count; | ||
| 643 | |||
| 644 | for (int i = 0; i < temp_rule.type_count; i++) { | ||
| 645 | char* temp_abbreviation = | ||
| 646 | temp_rule.chars.data() + temp_rule.ttis[i].abbreviation_list_index; | ||
| 647 | int j; | ||
| 648 | for (j = 0; j < char_count; j++) { | ||
| 649 | if (std::strcmp(time_zone_rule.chars.data() + j, temp_abbreviation) == 0) { | ||
| 650 | temp_rule.ttis[i].abbreviation_list_index = j; | ||
| 651 | have_abbreviation++; | ||
| 652 | break; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | if (j >= char_count) { | ||
| 656 | int temp_abbreviation_length = static_cast<int>(std::strlen(temp_abbreviation)); | ||
| 657 | if (j + temp_abbreviation_length < time_zone_max_chars) { | ||
| 658 | std::strcpy(time_zone_rule.chars.data() + j, temp_abbreviation); | ||
| 659 | char_count = j + temp_abbreviation_length + 1; | ||
| 660 | temp_rule.ttis[i].abbreviation_list_index = j; | ||
| 661 | have_abbreviation++; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | if (have_abbreviation == temp_rule.type_count) { | ||
| 667 | time_zone_rule.char_count = char_count; | ||
| 668 | |||
| 669 | // Original comment: | ||
| 670 | /* Ignore any trailing, no-op transitions generated | ||
| 671 | by zic as they don't help here and can run afoul | ||
| 672 | of bugs in zic 2016j or earlier. */ | ||
| 673 | // This is possibly unnecessary for yuzu, since Nintendo doesn't run zic | ||
| 674 | while (1 < time_zone_rule.time_count && | ||
| 675 | (time_zone_rule.types[time_zone_rule.time_count - 1] == | ||
| 676 | time_zone_rule.types[time_zone_rule.time_count - 2])) { | ||
| 677 | time_zone_rule.time_count--; | ||
| 678 | } | ||
| 679 | |||
| 680 | for (int i = 0; | ||
| 681 | i < temp_rule.time_count && time_zone_rule.time_count < time_zone_max_times; | ||
| 682 | i++) { | ||
| 683 | const s64 transition_time = temp_rule.ats[i]; | ||
| 684 | if (0 < time_zone_rule.time_count && | ||
| 685 | transition_time <= time_zone_rule.ats[time_zone_rule.time_count - 1]) { | ||
| 686 | continue; | ||
| 687 | } | ||
| 688 | |||
| 689 | time_zone_rule.ats[time_zone_rule.time_count] = transition_time; | ||
| 690 | time_zone_rule.types[time_zone_rule.time_count] = | ||
| 691 | static_cast<s8>(time_zone_rule.type_count + temp_rule.types[i]); | ||
| 692 | time_zone_rule.time_count++; | ||
| 693 | } | ||
| 694 | for (int i = 0; i < temp_rule.type_count; i++) { | ||
| 695 | time_zone_rule.ttis[time_zone_rule.type_count++] = temp_rule.ttis[i]; | ||
| 696 | } | ||
| 697 | } | ||
| 698 | } | ||
| 699 | } | ||
| 700 | |||
| 701 | const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool { | ||
| 702 | if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) { | ||
| 703 | return {}; | ||
| 704 | } | ||
| 705 | |||
| 706 | const struct TimeTypeInfo* ap = &rule.ttis[a]; | ||
| 707 | const struct TimeTypeInfo* bp = &rule.ttis[b]; | ||
| 708 | |||
| 709 | return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst && | ||
| 710 | (std::strcmp(&rule.chars[ap->abbreviation_list_index], | ||
| 711 | &rule.chars[bp->abbreviation_list_index]) == 0)); | ||
| 712 | }; | ||
| 713 | |||
| 714 | if (time_zone_rule.type_count == 0) { | ||
| 715 | return {}; | ||
| 716 | } | ||
| 717 | if (time_zone_rule.time_count > 1) { | ||
| 718 | if (time_zone_rule.ats[0] <= std::numeric_limits<s64>::max() - seconds_per_repeat) { | ||
| 719 | s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat; | ||
| 720 | int repeatattype = time_zone_rule.types[0]; | ||
| 721 | for (int i = 1; i < time_zone_rule.time_count; ++i) { | ||
| 722 | if (time_zone_rule.ats[i] == repeatat && | ||
| 723 | typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { | ||
| 724 | time_zone_rule.go_back = true; | ||
| 725 | break; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | } | ||
| 729 | if (std::numeric_limits<s64>::min() + seconds_per_repeat <= | ||
| 730 | time_zone_rule.ats[time_zone_rule.time_count - 1]) { | ||
| 731 | s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat; | ||
| 732 | int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1]; | ||
| 733 | for (int i = time_zone_rule.time_count; i >= 0; --i) { | ||
| 734 | if (time_zone_rule.ats[i] == repeatat && | ||
| 735 | typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { | ||
| 736 | time_zone_rule.go_ahead = true; | ||
| 737 | break; | ||
| 738 | } | ||
| 739 | } | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 743 | s32 default_type{}; | ||
| 744 | |||
| 745 | for (default_type = 0; default_type < time_zone_rule.time_count; default_type++) { | ||
| 746 | if (time_zone_rule.types[default_type] == 0) { | ||
| 747 | break; | ||
| 748 | } | ||
| 749 | } | ||
| 750 | |||
| 751 | default_type = default_type < time_zone_rule.time_count ? -1 : 0; | ||
| 752 | if (default_type < 0 && time_zone_rule.time_count > 0 && | ||
| 753 | time_zone_rule.ttis[time_zone_rule.types[0]].is_dst) { | ||
| 754 | default_type = time_zone_rule.types[0]; | ||
| 755 | while (--default_type >= 0) { | ||
| 756 | if (!time_zone_rule.ttis[default_type].is_dst) { | ||
| 757 | break; | ||
| 758 | } | ||
| 759 | } | ||
| 760 | } | ||
| 761 | if (default_type < 0) { | ||
| 762 | default_type = 0; | ||
| 763 | while (time_zone_rule.ttis[default_type].is_dst) { | ||
| 764 | if (++default_type >= time_zone_rule.type_count) { | ||
| 765 | default_type = 0; | ||
| 766 | break; | ||
| 767 | } | ||
| 768 | } | ||
| 769 | } | ||
| 770 | time_zone_rule.default_type = default_type; | ||
| 771 | return true; | ||
| 772 | } | ||
| 773 | |||
| 774 | static Result CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal& calendar_time, | ||
| 775 | CalendarAdditionalInfo& calendar_additional_info) { | ||
| 776 | s64 year{epoch_year}; | ||
| 777 | s64 time_days{time / seconds_per_day}; | ||
| 778 | s64 remaining_seconds{time % seconds_per_day}; | ||
| 779 | while (time_days < 0 || time_days >= GetYearLengthInDays(year)) { | ||
| 780 | s64 delta = time_days / days_per_leap_year; | ||
| 781 | if (!delta) { | ||
| 782 | delta = time_days < 0 ? -1 : 1; | ||
| 783 | } | ||
| 784 | s64 new_year{year}; | ||
| 785 | if (!SafeAdd(new_year, delta)) { | ||
| 786 | return ERROR_OUT_OF_RANGE; | ||
| 787 | } | ||
| 788 | time_days -= (new_year - year) * days_per_normal_year; | ||
| 789 | time_days -= GetLeapDaysFromYear(new_year - 1) - GetLeapDaysFromYear(year - 1); | ||
| 790 | year = new_year; | ||
| 791 | } | ||
| 792 | |||
| 793 | s64 day_of_year{time_days}; | ||
| 794 | remaining_seconds += gmt_offset; | ||
| 795 | while (remaining_seconds < 0) { | ||
| 796 | remaining_seconds += seconds_per_day; | ||
| 797 | day_of_year--; | ||
| 798 | } | ||
| 799 | |||
| 800 | while (remaining_seconds >= seconds_per_day) { | ||
| 801 | remaining_seconds -= seconds_per_day; | ||
| 802 | day_of_year++; | ||
| 803 | } | ||
| 804 | |||
| 805 | while (day_of_year < 0) { | ||
| 806 | if (!SafeAdd(year, -1)) { | ||
| 807 | return ERROR_OUT_OF_RANGE; | ||
| 808 | } | ||
| 809 | day_of_year += GetYearLengthInDays(year); | ||
| 810 | } | ||
| 811 | |||
| 812 | while (day_of_year >= GetYearLengthInDays(year)) { | ||
| 813 | day_of_year -= GetYearLengthInDays(year); | ||
| 814 | if (!SafeAdd(year, 1)) { | ||
| 815 | return ERROR_OUT_OF_RANGE; | ||
| 816 | } | ||
| 817 | } | ||
| 818 | |||
| 819 | calendar_time.year = year; | ||
| 820 | calendar_additional_info.day_of_year = static_cast<u32>(day_of_year); | ||
| 821 | s64 day_of_week{ | ||
| 822 | (epoch_week_day + | ||
| 823 | ((year - epoch_year) % days_per_week) * (days_per_normal_year % days_per_week) + | ||
| 824 | GetLeapDaysFromYear(year - 1) - GetLeapDaysFromYear(epoch_year - 1) + day_of_year) % | ||
| 825 | days_per_week}; | ||
| 826 | if (day_of_week < 0) { | ||
| 827 | day_of_week += days_per_week; | ||
| 828 | } | ||
| 829 | |||
| 830 | calendar_additional_info.day_of_week = static_cast<u32>(day_of_week); | ||
| 831 | calendar_time.hour = static_cast<s8>((remaining_seconds / seconds_per_hour) % seconds_per_hour); | ||
| 832 | remaining_seconds %= seconds_per_hour; | ||
| 833 | calendar_time.minute = static_cast<s8>(remaining_seconds / seconds_per_minute); | ||
| 834 | calendar_time.second = static_cast<s8>(remaining_seconds % seconds_per_minute); | ||
| 835 | |||
| 836 | for (calendar_time.month = 0; | ||
| 837 | day_of_year >= GetMonthLength(IsLeapYear(year), calendar_time.month); | ||
| 838 | ++calendar_time.month) { | ||
| 839 | day_of_year -= GetMonthLength(IsLeapYear(year), calendar_time.month); | ||
| 840 | } | ||
| 841 | |||
| 842 | calendar_time.day = static_cast<s8>(day_of_year + 1); | ||
| 843 | calendar_additional_info.is_dst = false; | ||
| 844 | calendar_additional_info.gmt_offset = gmt_offset; | ||
| 845 | |||
| 846 | return ResultSuccess; | ||
| 847 | } | ||
| 848 | |||
| 849 | static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, | ||
| 850 | CalendarTimeInternal& calendar_time, | ||
| 851 | CalendarAdditionalInfo& calendar_additional_info) { | ||
| 852 | ASSERT(rules.go_ahead ? rules.time_count > 0 : true); | ||
| 853 | if ((rules.go_back && time < rules.ats[0]) || | ||
| 854 | (rules.go_ahead && time > rules.ats[rules.time_count - 1])) { | ||
| 855 | s64 seconds{}; | ||
| 856 | if (time < rules.ats[0]) { | ||
| 857 | seconds = rules.ats[0] - time; | ||
| 858 | } else { | ||
| 859 | seconds = time - rules.ats[rules.time_count - 1]; | ||
| 860 | } | ||
| 861 | seconds--; | ||
| 862 | |||
| 863 | const s64 years{(seconds / seconds_per_repeat + 1) * years_per_repeat}; | ||
| 864 | seconds = years * average_seconds_per_year; | ||
| 865 | |||
| 866 | s64 new_time{time}; | ||
| 867 | if (time < rules.ats[0]) { | ||
| 868 | new_time += seconds; | ||
| 869 | } else { | ||
| 870 | new_time -= seconds; | ||
| 871 | } | ||
| 872 | if (new_time < rules.ats[0] && new_time > rules.ats[rules.time_count - 1]) { | ||
| 873 | return ERROR_TIME_NOT_FOUND; | ||
| 874 | } | ||
| 875 | if (const Result result{ | ||
| 876 | ToCalendarTimeInternal(rules, new_time, calendar_time, calendar_additional_info)}; | ||
| 877 | result != ResultSuccess) { | ||
| 878 | return result; | ||
| 879 | } | ||
| 880 | if (time < rules.ats[0]) { | ||
| 881 | calendar_time.year -= years; | ||
| 882 | } else { | ||
| 883 | calendar_time.year += years; | ||
| 884 | } | ||
| 885 | |||
| 886 | return ResultSuccess; | ||
| 887 | } | ||
| 888 | |||
| 889 | s32 tti_index{}; | ||
| 890 | if (rules.time_count == 0 || time < rules.ats[0]) { | ||
| 891 | tti_index = rules.default_type; | ||
| 892 | } else { | ||
| 893 | s32 low{1}; | ||
| 894 | s32 high{rules.time_count}; | ||
| 895 | while (low < high) { | ||
| 896 | s32 mid{(low + high) >> 1}; | ||
| 897 | if (time < rules.ats[mid]) { | ||
| 898 | high = mid; | ||
| 899 | } else { | ||
| 900 | low = mid + 1; | ||
| 901 | } | ||
| 902 | } | ||
| 903 | tti_index = rules.types[low - 1]; | ||
| 904 | } | ||
| 905 | |||
| 906 | if (const Result result{CreateCalendarTime(time, rules.ttis[tti_index].gmt_offset, | ||
| 907 | calendar_time, calendar_additional_info)}; | ||
| 908 | result != ResultSuccess) { | ||
| 909 | return result; | ||
| 910 | } | ||
| 911 | |||
| 912 | calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; | ||
| 913 | const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; | ||
| 914 | u32 index; | ||
| 915 | for (index = 0; time_zone[index] != '\0' && time_zone[index] != ',' && | ||
| 916 | index < calendar_additional_info.timezone_name.size() - 1; | ||
| 917 | ++index) { | ||
| 918 | calendar_additional_info.timezone_name[index] = time_zone[index]; | ||
| 919 | } | ||
| 920 | calendar_additional_info.timezone_name[index] = '\0'; | ||
| 921 | return ResultSuccess; | ||
| 922 | } | ||
| 923 | |||
| 924 | static Result ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) { | ||
| 925 | CalendarTimeInternal calendar_time{}; | ||
| 926 | const Result result{ | ||
| 927 | ToCalendarTimeInternal(rules, time, calendar_time, calendar.additional_info)}; | ||
| 928 | calendar.time.year = static_cast<s16>(calendar_time.year); | ||
| 929 | |||
| 930 | // Internal impl. uses 0-indexed month | ||
| 931 | calendar.time.month = static_cast<s8>(calendar_time.month + 1); | ||
| 932 | |||
| 933 | calendar.time.day = calendar_time.day; | ||
| 934 | calendar.time.hour = calendar_time.hour; | ||
| 935 | calendar.time.minute = calendar_time.minute; | ||
| 936 | calendar.time.second = calendar_time.second; | ||
| 937 | return result; | ||
| 938 | } | ||
| 939 | |||
| 940 | TimeZoneManager::TimeZoneManager() = default; | ||
| 941 | TimeZoneManager::~TimeZoneManager() = default; | ||
| 942 | |||
| 943 | Result TimeZoneManager::ToCalendarTime(const TimeZoneRule& rules, s64 time, | ||
| 944 | CalendarInfo& calendar) const { | ||
| 945 | return ToCalendarTimeImpl(rules, time, calendar); | ||
| 946 | } | ||
| 947 | |||
| 948 | Result TimeZoneManager::SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name, | ||
| 949 | FileSys::VirtualFile& vfs_file) { | ||
| 950 | TimeZoneRule rule{}; | ||
| 951 | if (ParseTimeZoneBinary(rule, vfs_file)) { | ||
| 952 | device_location_name = location_name; | ||
| 953 | time_zone_rule = rule; | ||
| 954 | return ResultSuccess; | ||
| 955 | } | ||
| 956 | return ERROR_TIME_ZONE_CONVERSION_FAILED; | ||
| 957 | } | ||
| 958 | |||
| 959 | Result TimeZoneManager::SetUpdatedTime(const Clock::SteadyClockTimePoint& value) { | ||
| 960 | time_zone_update_time_point = value; | ||
| 961 | return ResultSuccess; | ||
| 962 | } | ||
| 963 | |||
| 964 | Result TimeZoneManager::ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const { | ||
| 965 | if (is_initialized) { | ||
| 966 | return ToCalendarTime(time_zone_rule, time, calendar); | ||
| 967 | } else { | ||
| 968 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 969 | } | ||
| 970 | } | ||
| 971 | |||
| 972 | Result TimeZoneManager::ParseTimeZoneRuleBinary(TimeZoneRule& rules, | ||
| 973 | FileSys::VirtualFile& vfs_file) const { | ||
| 974 | if (!ParseTimeZoneBinary(rules, vfs_file)) { | ||
| 975 | return ERROR_TIME_ZONE_CONVERSION_FAILED; | ||
| 976 | } | ||
| 977 | return ResultSuccess; | ||
| 978 | } | ||
| 979 | |||
| 980 | Result TimeZoneManager::ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time, | ||
| 981 | s64& posix_time) const { | ||
| 982 | posix_time = 0; | ||
| 983 | |||
| 984 | CalendarTimeInternal internal_time{ | ||
| 985 | .year = calendar_time.year, | ||
| 986 | // Internal impl. uses 0-indexed month | ||
| 987 | .month = static_cast<s8>(calendar_time.month - 1), | ||
| 988 | .day = calendar_time.day, | ||
| 989 | .hour = calendar_time.hour, | ||
| 990 | .minute = calendar_time.minute, | ||
| 991 | .second = calendar_time.second, | ||
| 992 | }; | ||
| 993 | |||
| 994 | s32 hour{internal_time.hour}; | ||
| 995 | s32 minute{internal_time.minute}; | ||
| 996 | if (!SafeNormalize(hour, minute, minutes_per_hour)) { | ||
| 997 | return ERROR_OVERFLOW; | ||
| 998 | } | ||
| 999 | internal_time.minute = static_cast<s8>(minute); | ||
| 1000 | |||
| 1001 | s32 day{internal_time.day}; | ||
| 1002 | if (!SafeNormalize(day, hour, hours_per_day)) { | ||
| 1003 | return ERROR_OVERFLOW; | ||
| 1004 | } | ||
| 1005 | internal_time.day = static_cast<s8>(day); | ||
| 1006 | internal_time.hour = static_cast<s8>(hour); | ||
| 1007 | |||
| 1008 | s64 year{internal_time.year}; | ||
| 1009 | s64 month{internal_time.month}; | ||
| 1010 | if (!SafeNormalize(year, month, months_per_year)) { | ||
| 1011 | return ERROR_OVERFLOW; | ||
| 1012 | } | ||
| 1013 | internal_time.month = static_cast<s8>(month); | ||
| 1014 | |||
| 1015 | if (!SafeAdd(year, year_base)) { | ||
| 1016 | return ERROR_OVERFLOW; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | while (day <= 0) { | ||
| 1020 | if (!SafeAdd(year, -1)) { | ||
| 1021 | return ERROR_OVERFLOW; | ||
| 1022 | } | ||
| 1023 | s64 temp_year{year}; | ||
| 1024 | if (1 < internal_time.month) { | ||
| 1025 | ++temp_year; | ||
| 1026 | } | ||
| 1027 | day += static_cast<s32>(GetYearLengthInDays(temp_year)); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | while (day > days_per_leap_year) { | ||
| 1031 | s64 temp_year{year}; | ||
| 1032 | if (1 < internal_time.month) { | ||
| 1033 | temp_year++; | ||
| 1034 | } | ||
| 1035 | day -= static_cast<s32>(GetYearLengthInDays(temp_year)); | ||
| 1036 | if (!SafeAdd(year, 1)) { | ||
| 1037 | return ERROR_OVERFLOW; | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | while (true) { | ||
| 1042 | const s32 month_length{GetMonthLength(IsLeapYear(year), internal_time.month)}; | ||
| 1043 | if (day <= month_length) { | ||
| 1044 | break; | ||
| 1045 | } | ||
| 1046 | day -= month_length; | ||
| 1047 | internal_time.month++; | ||
| 1048 | if (internal_time.month >= months_per_year) { | ||
| 1049 | internal_time.month = 0; | ||
| 1050 | if (!SafeAdd(year, 1)) { | ||
| 1051 | return ERROR_OVERFLOW; | ||
| 1052 | } | ||
| 1053 | } | ||
| 1054 | } | ||
| 1055 | internal_time.day = static_cast<s8>(day); | ||
| 1056 | |||
| 1057 | if (!SafeAdd(year, -year_base)) { | ||
| 1058 | return ERROR_OVERFLOW; | ||
| 1059 | } | ||
| 1060 | internal_time.year = year; | ||
| 1061 | |||
| 1062 | s32 saved_seconds{}; | ||
| 1063 | if (internal_time.second >= 0 && internal_time.second < seconds_per_minute) { | ||
| 1064 | saved_seconds = 0; | ||
| 1065 | } else if (year + year_base < epoch_year) { | ||
| 1066 | s32 second{internal_time.second}; | ||
| 1067 | if (!SafeAdd(second, 1 - seconds_per_minute)) { | ||
| 1068 | return ERROR_OVERFLOW; | ||
| 1069 | } | ||
| 1070 | saved_seconds = second; | ||
| 1071 | internal_time.second = 1 - seconds_per_minute; | ||
| 1072 | } else { | ||
| 1073 | saved_seconds = internal_time.second; | ||
| 1074 | internal_time.second = 0; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | s64 low{LLONG_MIN}; | ||
| 1078 | s64 high{LLONG_MAX}; | ||
| 1079 | while (true) { | ||
| 1080 | s64 pivot{low / 2 + high / 2}; | ||
| 1081 | if (pivot < low) { | ||
| 1082 | pivot = low; | ||
| 1083 | } else if (pivot > high) { | ||
| 1084 | pivot = high; | ||
| 1085 | } | ||
| 1086 | s32 direction{}; | ||
| 1087 | CalendarTimeInternal candidate_calendar_time{}; | ||
| 1088 | CalendarAdditionalInfo unused{}; | ||
| 1089 | if (ToCalendarTimeInternal(rules, pivot, candidate_calendar_time, unused) != | ||
| 1090 | ResultSuccess) { | ||
| 1091 | if (pivot > 0) { | ||
| 1092 | direction = 1; | ||
| 1093 | } else { | ||
| 1094 | direction = -1; | ||
| 1095 | } | ||
| 1096 | } else { | ||
| 1097 | direction = candidate_calendar_time.Compare(internal_time); | ||
| 1098 | } | ||
| 1099 | if (!direction) { | ||
| 1100 | const s64 time_result{pivot + saved_seconds}; | ||
| 1101 | if ((time_result < pivot) != (saved_seconds < 0)) { | ||
| 1102 | return ERROR_OVERFLOW; | ||
| 1103 | } | ||
| 1104 | posix_time = time_result; | ||
| 1105 | break; | ||
| 1106 | } else { | ||
| 1107 | if (pivot == low) { | ||
| 1108 | if (pivot == LLONG_MAX) { | ||
| 1109 | return ERROR_TIME_NOT_FOUND; | ||
| 1110 | } | ||
| 1111 | pivot++; | ||
| 1112 | low++; | ||
| 1113 | } else if (pivot == high) { | ||
| 1114 | if (pivot == LLONG_MIN) { | ||
| 1115 | return ERROR_TIME_NOT_FOUND; | ||
| 1116 | } | ||
| 1117 | pivot--; | ||
| 1118 | high--; | ||
| 1119 | } | ||
| 1120 | if (low > high) { | ||
| 1121 | return ERROR_TIME_NOT_FOUND; | ||
| 1122 | } | ||
| 1123 | if (direction > 0) { | ||
| 1124 | high = pivot; | ||
| 1125 | } else { | ||
| 1126 | low = pivot; | ||
| 1127 | } | ||
| 1128 | } | ||
| 1129 | } | ||
| 1130 | return ResultSuccess; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | Result TimeZoneManager::ToPosixTimeWithMyRule(const CalendarTime& calendar_time, | ||
| 1134 | s64& posix_time) const { | ||
| 1135 | if (is_initialized) { | ||
| 1136 | return ToPosixTime(time_zone_rule, calendar_time, posix_time); | ||
| 1137 | } | ||
| 1138 | posix_time = 0; | ||
| 1139 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | Result TimeZoneManager::GetDeviceLocationName(LocationName& value) const { | ||
| 1143 | if (!is_initialized) { | ||
| 1144 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1145 | } | ||
| 1146 | std::memcpy(value.data(), device_location_name.c_str(), device_location_name.size()); | ||
| 1147 | return ResultSuccess; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | Result TimeZoneManager::GetTotalLocationNameCount(s32& count) const { | ||
| 1151 | if (!is_initialized) { | ||
| 1152 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1153 | } | ||
| 1154 | count = static_cast<u32>(total_location_name_count); | ||
| 1155 | |||
| 1156 | return ResultSuccess; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | Result TimeZoneManager::GetTimeZoneRuleVersion(u128& version) const { | ||
| 1160 | if (!is_initialized) { | ||
| 1161 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1162 | } | ||
| 1163 | version = time_zone_rule_version; | ||
| 1164 | |||
| 1165 | return ResultSuccess; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | Result TimeZoneManager::LoadLocationNameList(std::vector<LocationName>& values) const { | ||
| 1169 | if (!is_initialized) { | ||
| 1170 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | for (const auto& name : total_location_names) { | ||
| 1174 | LocationName entry{}; | ||
| 1175 | std::memcpy(entry.data(), name.c_str(), name.size()); | ||
| 1176 | values.push_back(entry); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | return ResultSuccess; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h deleted file mode 100644 index 8664f28d1..000000000 --- a/src/core/hle/service/time/time_zone_manager.h +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <string> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/file_sys/vfs_types.h" | ||
| 10 | #include "core/hle/service/time/clock_types.h" | ||
| 11 | #include "core/hle/service/time/time_zone_types.h" | ||
| 12 | |||
| 13 | namespace Service::Time::TimeZone { | ||
| 14 | |||
| 15 | class TimeZoneManager final { | ||
| 16 | public: | ||
| 17 | TimeZoneManager(); | ||
| 18 | ~TimeZoneManager(); | ||
| 19 | |||
| 20 | void SetTotalLocationNameCount(std::size_t value) { | ||
| 21 | total_location_name_count = value; | ||
| 22 | } | ||
| 23 | |||
| 24 | void SetLocationNames(std::vector<std::string> location_names) { | ||
| 25 | total_location_names = location_names; | ||
| 26 | } | ||
| 27 | |||
| 28 | void SetTimeZoneRuleVersion(const u128& value) { | ||
| 29 | time_zone_rule_version = value; | ||
| 30 | } | ||
| 31 | |||
| 32 | void MarkAsInitialized() { | ||
| 33 | is_initialized = true; | ||
| 34 | } | ||
| 35 | |||
| 36 | Result SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name, | ||
| 37 | FileSys::VirtualFile& vfs_file); | ||
| 38 | Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value); | ||
| 39 | Result GetDeviceLocationName(TimeZone::LocationName& value) const; | ||
| 40 | Result GetTotalLocationNameCount(s32& count) const; | ||
| 41 | Result GetTimeZoneRuleVersion(u128& version) const; | ||
| 42 | Result LoadLocationNameList(std::vector<TimeZone::LocationName>& values) const; | ||
| 43 | Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const; | ||
| 44 | Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const; | ||
| 45 | Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const; | ||
| 46 | Result ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time, | ||
| 47 | s64& posix_time) const; | ||
| 48 | Result ToPosixTimeWithMyRule(const CalendarTime& calendar_time, s64& posix_time) const; | ||
| 49 | |||
| 50 | private: | ||
| 51 | bool is_initialized{}; | ||
| 52 | TimeZoneRule time_zone_rule{}; | ||
| 53 | std::string device_location_name{"GMT"}; | ||
| 54 | u128 time_zone_rule_version{}; | ||
| 55 | std::size_t total_location_name_count{}; | ||
| 56 | std::vector<std::string> total_location_names{}; | ||
| 57 | Clock::SteadyClockTimePoint time_zone_update_time_point{ | ||
| 58 | Clock::SteadyClockTimePoint::GetRandom()}; | ||
| 59 | }; | ||
| 60 | |||
| 61 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp deleted file mode 100644 index 8171c82a5..000000000 --- a/src/core/hle/service/time/time_zone_service.cpp +++ /dev/null | |||
| @@ -1,217 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "core/hle/service/ipc_helpers.h" | ||
| 6 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 7 | #include "core/hle/service/time/time_zone_service.h" | ||
| 8 | #include "core/hle/service/time/time_zone_types.h" | ||
| 9 | |||
| 10 | namespace Service::Time { | ||
| 11 | |||
| 12 | ITimeZoneService::ITimeZoneService(Core::System& system_, | ||
| 13 | TimeZone::TimeZoneContentManager& time_zone_manager_) | ||
| 14 | : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} { | ||
| 15 | static const FunctionInfo functions[] = { | ||
| 16 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, | ||
| 17 | {1, nullptr, "SetDeviceLocationName"}, | ||
| 18 | {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"}, | ||
| 19 | {3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"}, | ||
| 20 | {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, | ||
| 21 | {5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, | ||
| 22 | {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, | ||
| 23 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, | ||
| 24 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | ||
| 25 | {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, | ||
| 26 | {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, | ||
| 27 | }; | ||
| 28 | RegisterHandlers(functions); | ||
| 29 | } | ||
| 30 | |||
| 31 | void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) { | ||
| 32 | LOG_DEBUG(Service_Time, "called"); | ||
| 33 | |||
| 34 | TimeZone::LocationName location_name{}; | ||
| 35 | if (const Result result{ | ||
| 36 | time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)}; | ||
| 37 | result != ResultSuccess) { | ||
| 38 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 39 | rb.Push(result); | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | |||
| 43 | IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2}; | ||
| 44 | rb.Push(ResultSuccess); | ||
| 45 | rb.PushRaw(location_name); | ||
| 46 | } | ||
| 47 | |||
| 48 | void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) { | ||
| 49 | LOG_DEBUG(Service_Time, "called"); | ||
| 50 | |||
| 51 | s32 count{}; | ||
| 52 | if (const Result result{ | ||
| 53 | time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)}; | ||
| 54 | result != ResultSuccess) { | ||
| 55 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 56 | rb.Push(result); | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | |||
| 60 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 61 | rb.Push(ResultSuccess); | ||
| 62 | rb.Push(count); | ||
| 63 | } | ||
| 64 | |||
| 65 | void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) { | ||
| 66 | LOG_DEBUG(Service_Time, "called"); | ||
| 67 | |||
| 68 | std::vector<TimeZone::LocationName> location_names{}; | ||
| 69 | if (const Result result{ | ||
| 70 | time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)}; | ||
| 71 | result != ResultSuccess) { | ||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 73 | rb.Push(result); | ||
| 74 | return; | ||
| 75 | } | ||
| 76 | |||
| 77 | ctx.WriteBuffer(location_names); | ||
| 78 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 79 | rb.Push(ResultSuccess); | ||
| 80 | rb.Push(static_cast<s32>(location_names.size())); | ||
| 81 | } | ||
| 82 | void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) { | ||
| 83 | LOG_DEBUG(Service_Time, "called"); | ||
| 84 | |||
| 85 | u128 rule_version{}; | ||
| 86 | if (const Result result{ | ||
| 87 | time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)}; | ||
| 88 | result != ResultSuccess) { | ||
| 89 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 90 | rb.Push(result); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 95 | rb.Push(ResultSuccess); | ||
| 96 | rb.PushRaw(rule_version); | ||
| 97 | } | ||
| 98 | |||
| 99 | void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) { | ||
| 100 | IPC::RequestParser rp{ctx}; | ||
| 101 | const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()}; | ||
| 102 | |||
| 103 | std::string location_name; | ||
| 104 | for (const auto& byte : raw_location_name) { | ||
| 105 | // Strip extra bytes | ||
| 106 | if (byte == '\0') { | ||
| 107 | break; | ||
| 108 | } | ||
| 109 | location_name.push_back(byte); | ||
| 110 | } | ||
| 111 | |||
| 112 | LOG_DEBUG(Service_Time, "called, location_name={}", location_name); | ||
| 113 | |||
| 114 | TimeZone::TimeZoneRule time_zone_rule{}; | ||
| 115 | const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)}; | ||
| 116 | |||
| 117 | std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule)); | ||
| 118 | std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule)); | ||
| 119 | ctx.WriteBuffer(time_zone_rule_outbuffer); | ||
| 120 | |||
| 121 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 122 | rb.Push(result); | ||
| 123 | } | ||
| 124 | |||
| 125 | void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) { | ||
| 126 | IPC::RequestParser rp{ctx}; | ||
| 127 | const auto posix_time{rp.Pop<s64>()}; | ||
| 128 | |||
| 129 | LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time); | ||
| 130 | |||
| 131 | TimeZone::TimeZoneRule time_zone_rule{}; | ||
| 132 | const auto buffer{ctx.ReadBuffer()}; | ||
| 133 | std::memcpy(&time_zone_rule, buffer.data(), buffer.size()); | ||
| 134 | |||
| 135 | TimeZone::CalendarInfo calendar_info{}; | ||
| 136 | if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime( | ||
| 137 | time_zone_rule, posix_time, calendar_info)}; | ||
| 138 | result != ResultSuccess) { | ||
| 139 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 140 | rb.Push(result); | ||
| 141 | return; | ||
| 142 | } | ||
| 143 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)}; | ||
| 145 | rb.Push(ResultSuccess); | ||
| 146 | rb.PushRaw(calendar_info); | ||
| 147 | } | ||
| 148 | |||
| 149 | void ITimeZoneService::ToCalendarTimeWithMyRule(HLERequestContext& ctx) { | ||
| 150 | IPC::RequestParser rp{ctx}; | ||
| 151 | const auto posix_time{rp.Pop<s64>()}; | ||
| 152 | |||
| 153 | LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time); | ||
| 154 | |||
| 155 | TimeZone::CalendarInfo calendar_info{}; | ||
| 156 | if (const Result result{ | ||
| 157 | time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules( | ||
| 158 | posix_time, calendar_info)}; | ||
| 159 | result != ResultSuccess) { | ||
| 160 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 161 | rb.Push(result); | ||
| 162 | return; | ||
| 163 | } | ||
| 164 | |||
| 165 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)}; | ||
| 166 | rb.Push(ResultSuccess); | ||
| 167 | rb.PushRaw(calendar_info); | ||
| 168 | } | ||
| 169 | |||
| 170 | void ITimeZoneService::ToPosixTime(HLERequestContext& ctx) { | ||
| 171 | LOG_DEBUG(Service_Time, "called"); | ||
| 172 | |||
| 173 | IPC::RequestParser rp{ctx}; | ||
| 174 | const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()}; | ||
| 175 | TimeZone::TimeZoneRule time_zone_rule{}; | ||
| 176 | std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule)); | ||
| 177 | |||
| 178 | s64 posix_time{}; | ||
| 179 | if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime( | ||
| 180 | time_zone_rule, calendar_time, posix_time)}; | ||
| 181 | result != ResultSuccess) { | ||
| 182 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 183 | rb.Push(result); | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | |||
| 187 | ctx.WriteBuffer(posix_time); | ||
| 188 | |||
| 189 | // TODO(bunnei): Handle multiple times | ||
| 190 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 191 | rb.Push(ResultSuccess); | ||
| 192 | rb.PushRaw<u32>(1); // Number of times we're returning | ||
| 193 | } | ||
| 194 | |||
| 195 | void ITimeZoneService::ToPosixTimeWithMyRule(HLERequestContext& ctx) { | ||
| 196 | LOG_DEBUG(Service_Time, "called"); | ||
| 197 | |||
| 198 | IPC::RequestParser rp{ctx}; | ||
| 199 | const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()}; | ||
| 200 | |||
| 201 | s64 posix_time{}; | ||
| 202 | if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTimeWithMyRule( | ||
| 203 | calendar_time, posix_time)}; | ||
| 204 | result != ResultSuccess) { | ||
| 205 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 206 | rb.Push(result); | ||
| 207 | return; | ||
| 208 | } | ||
| 209 | |||
| 210 | ctx.WriteBuffer(posix_time); | ||
| 211 | |||
| 212 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 213 | rb.Push(ResultSuccess); | ||
| 214 | rb.PushRaw<u32>(1); // Number of times we're returning | ||
| 215 | } | ||
| 216 | |||
| 217 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h deleted file mode 100644 index 952fcb0e2..000000000 --- a/src/core/hle/service/time/time_zone_service.h +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Core { | ||
| 9 | class System; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service::Time { | ||
| 13 | |||
| 14 | namespace TimeZone { | ||
| 15 | class TimeZoneContentManager; | ||
| 16 | } | ||
| 17 | |||
| 18 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { | ||
| 19 | public: | ||
| 20 | explicit ITimeZoneService(Core::System& system_, | ||
| 21 | TimeZone::TimeZoneContentManager& time_zone_manager_); | ||
| 22 | |||
| 23 | private: | ||
| 24 | void GetDeviceLocationName(HLERequestContext& ctx); | ||
| 25 | void GetTotalLocationNameCount(HLERequestContext& ctx); | ||
| 26 | void LoadLocationNameList(HLERequestContext& ctx); | ||
| 27 | void GetTimeZoneRuleVersion(HLERequestContext& ctx); | ||
| 28 | void LoadTimeZoneRule(HLERequestContext& ctx); | ||
| 29 | void ToCalendarTime(HLERequestContext& ctx); | ||
| 30 | void ToCalendarTimeWithMyRule(HLERequestContext& ctx); | ||
| 31 | void ToPosixTime(HLERequestContext& ctx); | ||
| 32 | void ToPosixTimeWithMyRule(HLERequestContext& ctx); | ||
| 33 | |||
| 34 | private: | ||
| 35 | TimeZone::TimeZoneContentManager& time_zone_content_manager; | ||
| 36 | }; | ||
| 37 | |||
| 38 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h deleted file mode 100644 index eb4fb52d1..000000000 --- a/src/core/hle/service/time/time_zone_types.h +++ /dev/null | |||
| @@ -1,86 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | |||
| 12 | namespace Service::Time::TimeZone { | ||
| 13 | |||
| 14 | using LocationName = std::array<char, 0x24>; | ||
| 15 | |||
| 16 | /// https://switchbrew.org/wiki/Glue_services#ttinfo | ||
| 17 | struct TimeTypeInfo { | ||
| 18 | s32 gmt_offset{}; | ||
| 19 | u8 is_dst{}; | ||
| 20 | INSERT_PADDING_BYTES(3); | ||
| 21 | s32 abbreviation_list_index{}; | ||
| 22 | u8 is_standard_time_daylight{}; | ||
| 23 | u8 is_gmt{}; | ||
| 24 | INSERT_PADDING_BYTES(2); | ||
| 25 | }; | ||
| 26 | static_assert(sizeof(TimeTypeInfo) == 0x10, "TimeTypeInfo is incorrect size"); | ||
| 27 | |||
| 28 | /// https://switchbrew.org/wiki/Glue_services#TimeZoneRule | ||
| 29 | struct TimeZoneRule { | ||
| 30 | s32 time_count{}; | ||
| 31 | s32 type_count{}; | ||
| 32 | s32 char_count{}; | ||
| 33 | u8 go_back{}; | ||
| 34 | u8 go_ahead{}; | ||
| 35 | INSERT_PADDING_BYTES(2); | ||
| 36 | std::array<s64, 1000> ats{}; | ||
| 37 | std::array<s8, 1000> types{}; | ||
| 38 | std::array<TimeTypeInfo, 128> ttis{}; | ||
| 39 | std::array<char, 512> chars{}; | ||
| 40 | s32 default_type{}; | ||
| 41 | INSERT_PADDING_BYTES(0x12C4); | ||
| 42 | }; | ||
| 43 | static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size"); | ||
| 44 | |||
| 45 | /// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo | ||
| 46 | struct CalendarAdditionalInfo { | ||
| 47 | u32 day_of_week; | ||
| 48 | u32 day_of_year; | ||
| 49 | std::array<char, 8> timezone_name; | ||
| 50 | u32 is_dst; | ||
| 51 | s32 gmt_offset; | ||
| 52 | }; | ||
| 53 | static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size"); | ||
| 54 | |||
| 55 | /// https://switchbrew.org/wiki/Glue_services#CalendarTime | ||
| 56 | struct CalendarTime { | ||
| 57 | s16 year; | ||
| 58 | s8 month; | ||
| 59 | s8 day; | ||
| 60 | s8 hour; | ||
| 61 | s8 minute; | ||
| 62 | s8 second; | ||
| 63 | INSERT_PADDING_BYTES_NOINIT(1); | ||
| 64 | }; | ||
| 65 | static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); | ||
| 66 | |||
| 67 | struct CalendarInfo { | ||
| 68 | CalendarTime time; | ||
| 69 | CalendarAdditionalInfo additional_info; | ||
| 70 | }; | ||
| 71 | static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size"); | ||
| 72 | |||
| 73 | struct TzifHeader { | ||
| 74 | u32_be magic{}; | ||
| 75 | u8 version{}; | ||
| 76 | INSERT_PADDING_BYTES(15); | ||
| 77 | s32_be ttis_gmt_count{}; | ||
| 78 | s32_be ttis_std_count{}; | ||
| 79 | s32_be leap_count{}; | ||
| 80 | s32_be time_count{}; | ||
| 81 | s32_be type_count{}; | ||
| 82 | s32_be char_count{}; | ||
| 83 | }; | ||
| 84 | static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader is incorrect size"); | ||
| 85 | |||
| 86 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp index 0e559a590..45b1a91dc 100644 --- a/src/tests/video_core/memory_tracker.cpp +++ b/src/tests/video_core/memory_tracker.cpp | |||
| @@ -545,4 +545,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") { | |||
| 545 | REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); | 545 | REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); |
| 546 | memory_track->MarkRegionAsCpuModified(c, WORD); | 546 | memory_track->MarkRegionAsCpuModified(c, WORD); |
| 547 | REQUIRE(rasterizer.Count() == 0); | 547 | REQUIRE(rasterizer.Count() == 0); |
| 548 | } \ No newline at end of file | 548 | } |
diff --git a/src/video_core/query_cache/query_base.h b/src/video_core/query_cache/query_base.h index aca6a6447..d5d21beaa 100644 --- a/src/video_core/query_cache/query_base.h +++ b/src/video_core/query_cache/query_base.h | |||
| @@ -67,4 +67,4 @@ public: | |||
| 67 | size_t size_slots{}; | 67 | size_t size_slots{}; |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | } // namespace VideoCommon \ No newline at end of file | 70 | } // namespace VideoCommon |
diff --git a/src/video_core/query_cache/query_cache_base.h b/src/video_core/query_cache/query_cache_base.h index c12fb75ef..00c25c8d6 100644 --- a/src/video_core/query_cache/query_cache_base.h +++ b/src/video_core/query_cache/query_cache_base.h | |||
| @@ -175,4 +175,4 @@ protected: | |||
| 175 | std::unique_ptr<QueryCacheBaseImpl> impl; | 175 | std::unique_ptr<QueryCacheBaseImpl> impl; |
| 176 | }; | 176 | }; |
| 177 | 177 | ||
| 178 | } // namespace VideoCommon \ No newline at end of file | 178 | } // namespace VideoCommon |
diff --git a/src/video_core/query_cache/query_stream.h b/src/video_core/query_cache/query_stream.h index d9040acd2..1d11b1275 100644 --- a/src/video_core/query_cache/query_stream.h +++ b/src/video_core/query_cache/query_stream.h | |||
| @@ -146,4 +146,4 @@ protected: | |||
| 146 | std::deque<size_t> old_queries; | 146 | std::deque<size_t> old_queries; |
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | } // namespace VideoCommon \ No newline at end of file | 149 | } // namespace VideoCommon |
diff --git a/src/video_core/query_cache/types.h b/src/video_core/query_cache/types.h index e9226bbfc..0c6a882e2 100644 --- a/src/video_core/query_cache/types.h +++ b/src/video_core/query_cache/types.h | |||
| @@ -71,4 +71,4 @@ enum class ReductionOp : u32 { | |||
| 71 | MaxReductionOp, | 71 | MaxReductionOp, |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | } // namespace VideoCommon \ No newline at end of file | 74 | } // namespace VideoCommon |
diff --git a/src/video_core/rasterizer_download_area.h b/src/video_core/rasterizer_download_area.h index 2d7425c79..d28826043 100644 --- a/src/video_core/rasterizer_download_area.h +++ b/src/video_core/rasterizer_download_area.h | |||
| @@ -13,4 +13,4 @@ struct RasterizerDownloadArea { | |||
| 13 | bool preemtive; | 13 | bool preemtive; |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | } // namespace VideoCore \ No newline at end of file | 16 | } // namespace VideoCore |
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h index bd6696b07..4aada5a00 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h | |||
| @@ -84,4 +84,4 @@ private: | |||
| 84 | std::vector<std::unique_ptr<DescriptorBank>> banks; | 84 | std::vector<std::unique_ptr<DescriptorBank>> banks; |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | } // namespace Vulkan \ No newline at end of file | 87 | } // namespace Vulkan |
diff --git a/src/video_core/texture_cache/accelerated_swizzle.cpp b/src/video_core/texture_cache/accelerated_swizzle.cpp index 70be1657e..4c3f724d7 100644 --- a/src/video_core/texture_cache/accelerated_swizzle.cpp +++ b/src/video_core/texture_cache/accelerated_swizzle.cpp | |||
| @@ -66,4 +66,4 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter | |||
| 66 | }; | 66 | }; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | } // namespace VideoCommon::Accelerated \ No newline at end of file | 69 | } // namespace VideoCommon::Accelerated |
diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 3a7f6101d..9fd094ab6 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp | |||
| @@ -494,4 +494,4 @@ QString ConfigureRingController::AnalogToText(const Common::ParamPackage& param, | |||
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | return QObject::tr("[unknown]"); | 496 | return QObject::tr("[unknown]"); |
| 497 | } \ No newline at end of file | 497 | } |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index b0b84f967..e193b5f95 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -12,9 +12,10 @@ | |||
| 12 | #include <QGraphicsItem> | 12 | #include <QGraphicsItem> |
| 13 | #include <QLineEdit> | 13 | #include <QLineEdit> |
| 14 | #include <QMessageBox> | 14 | #include <QMessageBox> |
| 15 | #include <QSpinBox> | ||
| 16 | |||
| 15 | #include "common/settings.h" | 17 | #include "common/settings.h" |
| 16 | #include "core/core.h" | 18 | #include "core/core.h" |
| 17 | #include "core/hle/service/time/time_manager.h" | ||
| 18 | #include "ui_configure_system.h" | 19 | #include "ui_configure_system.h" |
| 19 | #include "yuzu/configuration/configuration_shared.h" | 20 | #include "yuzu/configuration/configuration_shared.h" |
| 20 | #include "yuzu/configuration/configure_system.h" | 21 | #include "yuzu/configuration/configure_system.h" |
| @@ -49,6 +50,11 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, | |||
| 49 | : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} { | 50 | : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} { |
| 50 | ui->setupUi(this); | 51 | ui->setupUi(this); |
| 51 | 52 | ||
| 53 | const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); | ||
| 54 | const auto current_time_s = | ||
| 55 | std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); | ||
| 56 | previous_time = current_time_s + Settings::values.custom_rtc_offset.GetValue(); | ||
| 57 | |||
| 52 | Setup(builder); | 58 | Setup(builder); |
| 53 | 59 | ||
| 54 | const auto locale_check = [this]() { | 60 | const auto locale_check = [this]() { |
| @@ -64,13 +70,28 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, | |||
| 64 | } | 70 | } |
| 65 | }; | 71 | }; |
| 66 | 72 | ||
| 73 | const auto update_date_offset = [this]() { | ||
| 74 | if (!checkbox_rtc->isChecked()) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | auto offset = date_rtc_offset->value(); | ||
| 78 | offset += date_rtc->dateTime().toSecsSinceEpoch() - previous_time; | ||
| 79 | previous_time = date_rtc->dateTime().toSecsSinceEpoch(); | ||
| 80 | date_rtc_offset->setValue(offset); | ||
| 81 | }; | ||
| 82 | const auto update_rtc_date = [this]() { UpdateRtcTime(); }; | ||
| 83 | |||
| 67 | connect(combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check); | 84 | connect(combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check); |
| 68 | connect(combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check); | 85 | connect(combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check); |
| 86 | connect(checkbox_rtc, qOverload<int>(&QCheckBox::stateChanged), this, update_rtc_date); | ||
| 87 | connect(date_rtc_offset, qOverload<int>(&QSpinBox::valueChanged), this, update_rtc_date); | ||
| 88 | connect(date_rtc, &QDateTimeEdit::dateTimeChanged, this, update_date_offset); | ||
| 69 | 89 | ||
| 70 | ui->label_warn_invalid_locale->setVisible(false); | 90 | ui->label_warn_invalid_locale->setVisible(false); |
| 71 | locale_check(); | 91 | locale_check(); |
| 72 | 92 | ||
| 73 | SetConfiguration(); | 93 | SetConfiguration(); |
| 94 | UpdateRtcTime(); | ||
| 74 | } | 95 | } |
| 75 | 96 | ||
| 76 | ConfigureSystem::~ConfigureSystem() = default; | 97 | ConfigureSystem::~ConfigureSystem() = default; |
| @@ -120,14 +141,28 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) { | |||
| 120 | continue; | 141 | continue; |
| 121 | } | 142 | } |
| 122 | 143 | ||
| 144 | // Keep track of the region_index (and language_index) combobox to validate the selected | ||
| 145 | // settings | ||
| 123 | if (setting->Id() == Settings::values.region_index.Id()) { | 146 | if (setting->Id() == Settings::values.region_index.Id()) { |
| 124 | // Keep track of the region_index (and language_index) combobox to validate the selected | ||
| 125 | // settings | ||
| 126 | combo_region = widget->combobox; | 147 | combo_region = widget->combobox; |
| 127 | } else if (setting->Id() == Settings::values.language_index.Id()) { | 148 | } |
| 149 | |||
| 150 | if (setting->Id() == Settings::values.language_index.Id()) { | ||
| 128 | combo_language = widget->combobox; | 151 | combo_language = widget->combobox; |
| 129 | } | 152 | } |
| 130 | 153 | ||
| 154 | if (setting->Id() == Settings::values.custom_rtc.Id()) { | ||
| 155 | checkbox_rtc = widget->checkbox; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (setting->Id() == Settings::values.custom_rtc.Id()) { | ||
| 159 | date_rtc = widget->date_time_edit; | ||
| 160 | } | ||
| 161 | |||
| 162 | if (setting->Id() == Settings::values.custom_rtc_offset.Id()) { | ||
| 163 | date_rtc_offset = widget->spinbox; | ||
| 164 | } | ||
| 165 | |||
| 131 | switch (setting->GetCategory()) { | 166 | switch (setting->GetCategory()) { |
| 132 | case Settings::Category::Core: | 167 | case Settings::Category::Core: |
| 133 | core_hold.emplace(setting->Id(), widget); | 168 | core_hold.emplace(setting->Id(), widget); |
| @@ -147,6 +182,19 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) { | |||
| 147 | } | 182 | } |
| 148 | } | 183 | } |
| 149 | 184 | ||
| 185 | void ConfigureSystem::UpdateRtcTime() { | ||
| 186 | const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); | ||
| 187 | previous_time = std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); | ||
| 188 | date_rtc_offset->setEnabled(checkbox_rtc->isChecked()); | ||
| 189 | |||
| 190 | if (checkbox_rtc->isChecked()) { | ||
| 191 | previous_time += date_rtc_offset->value(); | ||
| 192 | } | ||
| 193 | |||
| 194 | const auto date = QDateTime::fromSecsSinceEpoch(previous_time); | ||
| 195 | date_rtc->setDateTime(date); | ||
| 196 | } | ||
| 197 | |||
| 150 | void ConfigureSystem::SetConfiguration() {} | 198 | void ConfigureSystem::SetConfiguration() {} |
| 151 | 199 | ||
| 152 | void ConfigureSystem::ApplyConfiguration() { | 200 | void ConfigureSystem::ApplyConfiguration() { |
| @@ -154,4 +202,5 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 154 | for (const auto& func : apply_funcs) { | 202 | for (const auto& func : apply_funcs) { |
| 155 | func(powered_on); | 203 | func(powered_on); |
| 156 | } | 204 | } |
| 205 | UpdateRtcTime(); | ||
| 157 | } | 206 | } |
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index eab99a48a..4334211f9 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h | |||
| @@ -43,6 +43,8 @@ private: | |||
| 43 | 43 | ||
| 44 | void Setup(const ConfigurationShared::Builder& builder); | 44 | void Setup(const ConfigurationShared::Builder& builder); |
| 45 | 45 | ||
| 46 | void UpdateRtcTime(); | ||
| 47 | |||
| 46 | std::vector<std::function<void(bool)>> apply_funcs{}; | 48 | std::vector<std::function<void(bool)>> apply_funcs{}; |
| 47 | 49 | ||
| 48 | std::unique_ptr<Ui::ConfigureSystem> ui; | 50 | std::unique_ptr<Ui::ConfigureSystem> ui; |
| @@ -52,4 +54,8 @@ private: | |||
| 52 | 54 | ||
| 53 | QComboBox* combo_region; | 55 | QComboBox* combo_region; |
| 54 | QComboBox* combo_language; | 56 | QComboBox* combo_language; |
| 57 | QCheckBox* checkbox_rtc; | ||
| 58 | QDateTimeEdit* date_rtc; | ||
| 59 | QSpinBox* date_rtc_offset; | ||
| 60 | u64 previous_time; | ||
| 55 | }; | 61 | }; |
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 922eb1b1a..ed9c7d859 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp | |||
| @@ -143,8 +143,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { | |||
| 143 | INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral()); | 143 | INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral()); |
| 144 | INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral()); | 144 | INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral()); |
| 145 | INSERT(Settings, device_name, tr("Device Name"), QStringLiteral()); | 145 | INSERT(Settings, device_name, tr("Device Name"), QStringLiteral()); |
| 146 | INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral()); | 146 | INSERT(Settings, custom_rtc, tr("Custom RTC Date:"), QStringLiteral()); |
| 147 | INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral()); | 147 | INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral()); |
| 148 | INSERT(Settings, custom_rtc_offset, QStringLiteral(" "), | ||
| 149 | QStringLiteral("The number of seconds from the current unix time")); | ||
| 148 | INSERT(Settings, language_index, tr("Language:"), | 150 | INSERT(Settings, language_index, tr("Language:"), |
| 149 | tr("Note: this can be overridden when region setting is auto-select")); | 151 | tr("Note: this can be overridden when region setting is auto-select")); |
| 150 | INSERT(Settings, region_index, tr("Region:"), QStringLiteral()); | 152 | INSERT(Settings, region_index, tr("Region:"), QStringLiteral()); |
diff --git a/src/yuzu/debugger/console.h b/src/yuzu/debugger/console.h index fdb7d174c..2491d1ec1 100644 --- a/src/yuzu/debugger/console.h +++ b/src/yuzu/debugger/console.h | |||
| @@ -10,4 +10,4 @@ namespace Debugger { | |||
| 10 | * get a real qt logging window which would work for all platforms. | 10 | * get a real qt logging window which would work for all platforms. |
| 11 | */ | 11 | */ |
| 12 | void ToggleConsole(); | 12 | void ToggleConsole(); |
| 13 | } // namespace Debugger \ No newline at end of file | 13 | } // namespace Debugger |