early-access version 4053

This commit is contained in:
pineappleEA 2024-01-08 22:24:26 +01:00
parent 60e6d50f8f
commit 14bc41806f
172 changed files with 10634 additions and 446 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) <year> <owner> Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View file

@ -1,4 +1,4 @@
Copyright (c) <year> <owner>. Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View file

@ -35,7 +35,7 @@ Mozilla Public License Version 2.0
means any form of the work other than Source Code Form. means any form of the work other than Source Code Form.
1.7. "Larger Work" 1.7. "Larger Work"
means a work that combines Covered Software with other material, in means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software. a separate file or files, that is not Covered Software.
1.8. "License" 1.8. "License"

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 4052. This is the source code for early-access 4053.
## Legal Notice ## Legal Notice

View file

@ -178,6 +178,9 @@ if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb) add_library(stb::headers ALIAS stb)
endif() endif()
add_library(tz tz/tz/tz.cpp)
target_include_directories(tz PUBLIC ./tz)
add_library(bc_decoder bc_decoder/bc_decoder.cpp) add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder) target_include_directories(bc_decoder PUBLIC ./bc_decoder)

View file

@ -138,7 +138,7 @@ if (NOT WIN32 AND NOT ANDROID)
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
--sysroot=${SYSROOT} --sysroot=${SYSROOT}
--target-os=android --target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib" --extra-ldflags="-nostdlib"
) )
endif() endif()

1636
externals/tz/tz/tz.cpp vendored Executable file

File diff suppressed because it is too large Load diff

81
externals/tz/tz/tz.h vendored Executable file
View file

@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 1996 Arthur David Olson
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include <cstdint>
#include <limits>
#include <span>
#include <array>
#include <time.h>
namespace Tz {
using u8 = uint8_t;
using s8 = int8_t;
using u16 = uint16_t;
using s16 = int16_t;
using u32 = uint32_t;
using s32 = int32_t;
using u64 = uint64_t;
using s64 = int64_t;
constexpr size_t TZ_MAX_TIMES = 1000;
constexpr size_t TZ_MAX_TYPES = 128;
constexpr size_t TZ_MAX_CHARS = 50;
constexpr size_t MY_TZNAME_MAX = 255;
constexpr size_t TZNAME_MAXIMUM = 255;
constexpr size_t TZ_MAX_LEAPS = 50;
constexpr s64 TIME_T_MAX = std::numeric_limits<s64>::max();
constexpr s64 TIME_T_MIN = std::numeric_limits<s64>::min();
constexpr size_t CHARS_EXTRA = 3;
constexpr size_t MAX_ZONE_CHARS = std::max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof("UTC"));
constexpr size_t MAX_TZNAME_CHARS = 2 * (MY_TZNAME_MAX + 1);
struct ttinfo {
s32 tt_utoff;
bool tt_isdst;
s32 tt_desigidx;
bool tt_ttisstd;
bool tt_ttisut;
};
static_assert(sizeof(ttinfo) == 0x10, "ttinfo has the wrong size!");
struct Rule {
s32 timecnt;
s32 typecnt;
s32 charcnt;
bool goback;
bool goahead;
std::array <u8, 0x2> padding0;
std::array<s64, TZ_MAX_TIMES> ats;
std::array<u8, TZ_MAX_TIMES> types;
std::array<ttinfo, TZ_MAX_TYPES> ttis;
std::array<char, std::max(MAX_ZONE_CHARS, MAX_TZNAME_CHARS)> chars;
s32 defaulttype;
std::array <u8, 0x12C4> padding1;
};
static_assert(sizeof(Rule) == 0x4000, "Rule has the wrong size!");
struct CalendarTimeInternal {
s32 tm_sec;
s32 tm_min;
s32 tm_hour;
s32 tm_mday;
s32 tm_mon;
s32 tm_year;
s32 tm_wday;
s32 tm_yday;
s32 tm_isdst;
std::array<char, 16> tm_zone;
s32 tm_utoff;
s32 time_index;
};
static_assert(sizeof(CalendarTimeInternal) == 0x3C, "CalendarTimeInternal has the wrong size!");
s32 ParseTimeZoneBinary(Rule& out_rule, std::span<const u8> binary);
bool localtime_rz(CalendarTimeInternal* tmp, Rule* sp, time_t* timep);
u32 mktime_tzname(time_t* out_time, Rule* sp, CalendarTimeInternal* tmp);
} // namespace Tz

View file

@ -21,7 +21,7 @@ void AndroidConfig::ReloadAllValues() {
} }
void AndroidConfig::SaveAllValues() { void AndroidConfig::SaveAllValues() {
Save(); SaveValues();
SaveAndroidValues(); SaveAndroidValues();
} }

View file

@ -29,28 +29,32 @@ NativeClock::NativeClock() {
gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq);
} }
void NativeClock::Reset() {
start_ticks = GetUptime();
}
std::chrono::nanoseconds NativeClock::GetTimeNS() const { std::chrono::nanoseconds NativeClock::GetTimeNS() const {
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)}; return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)};
} }
std::chrono::microseconds NativeClock::GetTimeUS() const { std::chrono::microseconds NativeClock::GetTimeUS() const {
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)}; return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)};
} }
std::chrono::milliseconds NativeClock::GetTimeMS() const { std::chrono::milliseconds NativeClock::GetTimeMS() const {
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)}; return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)};
} }
u64 NativeClock::GetCNTPCT() const { s64 NativeClock::GetCNTPCT() const {
return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor); return MultiplyHigh(GetUptime() - start_ticks, guest_cntfrq_factor);
} }
u64 NativeClock::GetGPUTick() const { s64 NativeClock::GetGPUTick() const {
return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor); return MultiplyHigh(GetUptime() - start_ticks, gputick_cntfrq_factor);
} }
u64 NativeClock::GetHostTicksNow() const { s64 NativeClock::GetUptime() const {
u64 cntvct_el0 = 0; s64 cntvct_el0 = 0;
asm volatile("dsb ish\n\t" asm volatile("dsb ish\n\t"
"mrs %[cntvct_el0], cntvct_el0\n\t" "mrs %[cntvct_el0], cntvct_el0\n\t"
"dsb ish\n\t" "dsb ish\n\t"
@ -58,15 +62,11 @@ u64 NativeClock::GetHostTicksNow() const {
return cntvct_el0; return cntvct_el0;
} }
u64 NativeClock::GetHostTicksElapsed() const {
return GetHostTicksNow();
}
bool NativeClock::IsNative() const { bool NativeClock::IsNative() const {
return true; return true;
} }
u64 NativeClock::GetHostCNTFRQ() { s64 NativeClock::GetHostCNTFRQ() {
u64 cntfrq_el0 = 0; u64 cntfrq_el0 = 0;
std::string_view board{""}; std::string_view board{""};
#ifdef ANDROID #ifdef ANDROID

View file

@ -11,23 +11,23 @@ class NativeClock final : public WallClock {
public: public:
explicit NativeClock(); explicit NativeClock();
void Reset() override;
std::chrono::nanoseconds GetTimeNS() const override; std::chrono::nanoseconds GetTimeNS() const override;
std::chrono::microseconds GetTimeUS() const override; std::chrono::microseconds GetTimeUS() const override;
std::chrono::milliseconds GetTimeMS() const override; std::chrono::milliseconds GetTimeMS() const override;
u64 GetCNTPCT() const override; s64 GetCNTPCT() const override;
u64 GetGPUTick() const override; s64 GetGPUTick() const override;
u64 GetHostTicksNow() const override; s64 GetUptime() const override;
u64 GetHostTicksElapsed() const override;
bool IsNative() const override; bool IsNative() const override;
static u64 GetHostCNTFRQ(); static s64 GetHostCNTFRQ();
public: public:
using FactorType = unsigned __int128; using FactorType = unsigned __int128;
@ -42,6 +42,7 @@ private:
FactorType ms_cntfrq_factor; FactorType ms_cntfrq_factor;
FactorType guest_cntfrq_factor; FactorType guest_cntfrq_factor;
FactorType gputick_cntfrq_factor; FactorType gputick_cntfrq_factor;
s64 start_ticks;
}; };
} // namespace Common::Arm64 } // namespace Common::Arm64

View file

@ -18,4 +18,4 @@ struct MemoryInfo {
*/ */
[[nodiscard]] const MemoryInfo& GetMemInfo(); [[nodiscard]] const MemoryInfo& GetMemInfo();
} // namespace Common } // namespace Common

View file

@ -12,9 +12,8 @@
namespace Common { namespace Common {
struct UUID { struct UUID {
std::array<u8, 0x10> uuid{}; std::array<u8, 0x10> uuid;
/// Constructs an invalid UUID.
constexpr UUID() = default; constexpr UUID() = default;
/// Constructs a UUID from a reference to a 128 bit array. /// Constructs a UUID from a reference to a 128 bit array.
@ -34,14 +33,6 @@ struct UUID {
*/ */
explicit UUID(std::string_view uuid_string); explicit UUID(std::string_view uuid_string);
~UUID() = default;
constexpr UUID(const UUID&) noexcept = default;
constexpr UUID(UUID&&) noexcept = default;
constexpr UUID& operator=(const UUID&) noexcept = default;
constexpr UUID& operator=(UUID&&) noexcept = default;
/** /**
* Returns whether the stored UUID is valid or not. * Returns whether the stored UUID is valid or not.
* *
@ -121,6 +112,7 @@ struct UUID {
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
}; };
static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size."); static_assert(sizeof(UUID) == 0x10, "UUID has incorrect size.");
static_assert(std::is_trivial_v<UUID>);
/// An invalid UUID. This UUID has all its bytes set to 0. /// An invalid UUID. This UUID has all its bytes set to 0.
constexpr UUID InvalidUUID = {}; constexpr UUID InvalidUUID = {};

View file

@ -18,34 +18,39 @@ namespace Common {
class StandardWallClock final : public WallClock { class StandardWallClock final : public WallClock {
public: public:
explicit StandardWallClock() : start_time{SteadyClock::Now()} {} explicit StandardWallClock() {}
void Reset() override {
start_time = std::chrono::system_clock::now();
}
std::chrono::nanoseconds GetTimeNS() const override { std::chrono::nanoseconds GetTimeNS() const override {
return SteadyClock::Now() - start_time; return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch());
} }
std::chrono::microseconds GetTimeUS() const override { std::chrono::microseconds GetTimeUS() const override {
return static_cast<std::chrono::microseconds>(GetHostTicksElapsed() / NsToUsRatio::den); return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch());
} }
std::chrono::milliseconds GetTimeMS() const override { std::chrono::milliseconds GetTimeMS() const override {
return static_cast<std::chrono::milliseconds>(GetHostTicksElapsed() / NsToMsRatio::den); return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
} }
u64 GetCNTPCT() const override { s64 GetCNTPCT() const override {
return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
} }
u64 GetGPUTick() const override { s64 GetGPUTick() const override {
return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
} }
u64 GetHostTicksNow() const override { s64 GetUptime() const override {
return static_cast<u64>(SteadyClock::Now().time_since_epoch().count()); return std::chrono::duration_cast<std::chrono::nanoseconds>(
} std::chrono::system_clock::now() - start_time)
.count();
u64 GetHostTicksElapsed() const override {
return static_cast<u64>(GetTimeNS().count());
} }
bool IsNative() const override { bool IsNative() const override {
@ -53,7 +58,7 @@ public:
} }
private: private:
SteadyClock::time_point start_time; std::chrono::system_clock::time_point start_time{};
}; };
std::unique_ptr<WallClock> CreateOptimalClock() { std::unique_ptr<WallClock> CreateOptimalClock() {

View file

@ -19,6 +19,8 @@ public:
virtual ~WallClock() = default; virtual ~WallClock() = default;
virtual void Reset() = 0;
/// @returns The time in nanoseconds since the construction of this clock. /// @returns The time in nanoseconds since the construction of this clock.
virtual std::chrono::nanoseconds GetTimeNS() const = 0; virtual std::chrono::nanoseconds GetTimeNS() const = 0;
@ -29,16 +31,13 @@ public:
virtual std::chrono::milliseconds GetTimeMS() const = 0; virtual std::chrono::milliseconds GetTimeMS() const = 0;
/// @returns The guest CNTPCT ticks since the construction of this clock. /// @returns The guest CNTPCT ticks since the construction of this clock.
virtual u64 GetCNTPCT() const = 0; virtual s64 GetCNTPCT() const = 0;
/// @returns The guest GPU ticks since the construction of this clock. /// @returns The guest GPU ticks since the construction of this clock.
virtual u64 GetGPUTick() const = 0; virtual s64 GetGPUTick() const = 0;
/// @returns The raw host timer ticks since an indeterminate epoch. /// @returns The raw host timer ticks since an indeterminate epoch.
virtual u64 GetHostTicksNow() const = 0; virtual s64 GetUptime() const = 0;
/// @returns The raw host timer ticks since the construction of this clock.
virtual u64 GetHostTicksElapsed() const = 0;
/// @returns Whether the clock directly uses the host's hardware clock. /// @returns Whether the clock directly uses the host's hardware clock.
virtual bool IsNative() const = 0; virtual bool IsNative() const = 0;

View file

@ -8,39 +8,39 @@
namespace Common::X64 { namespace Common::X64 {
NativeClock::NativeClock(u64 rdtsc_frequency_) NativeClock::NativeClock(u64 rdtsc_frequency_)
: start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_}, : rdtsc_frequency{rdtsc_frequency_}, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den,
ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)}, rdtsc_frequency)},
us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)},
ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)},
cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)},
gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {}
void NativeClock::Reset() {
start_ticks = FencedRDTSC();
}
std::chrono::nanoseconds NativeClock::GetTimeNS() const { std::chrono::nanoseconds NativeClock::GetTimeNS() const {
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)}; return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)};
} }
std::chrono::microseconds NativeClock::GetTimeUS() const { std::chrono::microseconds NativeClock::GetTimeUS() const {
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)}; return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)};
} }
std::chrono::milliseconds NativeClock::GetTimeMS() const { std::chrono::milliseconds NativeClock::GetTimeMS() const {
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)}; return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)};
} }
u64 NativeClock::GetCNTPCT() const { s64 NativeClock::GetCNTPCT() const {
return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor); return MultiplyHigh(GetUptime() - start_ticks, cntpct_rdtsc_factor);
} }
u64 NativeClock::GetGPUTick() const { s64 NativeClock::GetGPUTick() const {
return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor); return MultiplyHigh(GetUptime() - start_ticks, gputick_rdtsc_factor);
} }
u64 NativeClock::GetHostTicksNow() const { s64 NativeClock::GetUptime() const {
return FencedRDTSC(); return static_cast<s64>(FencedRDTSC());
}
u64 NativeClock::GetHostTicksElapsed() const {
return FencedRDTSC() - start_ticks;
} }
bool NativeClock::IsNative() const { bool NativeClock::IsNative() const {

View file

@ -11,19 +11,19 @@ class NativeClock final : public WallClock {
public: public:
explicit NativeClock(u64 rdtsc_frequency_); explicit NativeClock(u64 rdtsc_frequency_);
void Reset() override;
std::chrono::nanoseconds GetTimeNS() const override; std::chrono::nanoseconds GetTimeNS() const override;
std::chrono::microseconds GetTimeUS() const override; std::chrono::microseconds GetTimeUS() const override;
std::chrono::milliseconds GetTimeMS() const override; std::chrono::milliseconds GetTimeMS() const override;
u64 GetCNTPCT() const override; s64 GetCNTPCT() const override;
u64 GetGPUTick() const override; s64 GetGPUTick() const override;
u64 GetHostTicksNow() const override; s64 GetUptime() const override;
u64 GetHostTicksElapsed() const override;
bool IsNative() const override; bool IsNative() const override;

View file

@ -511,6 +511,24 @@ add_library(core STATIC
hle/service/glue/glue_manager.h hle/service/glue/glue_manager.h
hle/service/glue/notif.cpp hle/service/glue/notif.cpp
hle/service/glue/notif.h hle/service/glue/notif.h
hle/service/glue/time/alarm_worker.cpp
hle/service/glue/time/alarm_worker.h
hle/service/glue/time/file_timestamp_worker.cpp
hle/service/glue/time/file_timestamp_worker.h
hle/service/glue/time/manager.cpp
hle/service/glue/time/manager.h
hle/service/glue/time/pm_state_change_handler.cpp
hle/service/glue/time/pm_state_change_handler.h
hle/service/glue/time/standard_steady_clock_resource.cpp
hle/service/glue/time/standard_steady_clock_resource.h
hle/service/glue/time/static.cpp
hle/service/glue/time/static.h
hle/service/glue/time/time_zone.cpp
hle/service/glue/time/time_zone.h
hle/service/glue/time/time_zone_binary.cpp
hle/service/glue/time/time_zone_binary.h
hle/service/glue/time/worker.cpp
hle/service/glue/time/worker.h
hle/service/grc/grc.cpp hle/service/grc/grc.cpp
hle/service/grc/grc.h hle/service/grc/grc.h
hle/service/hid/hid.cpp hle/service/hid/hid.cpp
@ -689,6 +707,46 @@ add_library(core STATIC
hle/service/prepo/prepo.h hle/service/prepo/prepo.h
hle/service/psc/psc.cpp hle/service/psc/psc.cpp
hle/service/psc/psc.h hle/service/psc/psc.h
hle/service/psc/time/alarms.cpp
hle/service/psc/time/alarms.h
hle/service/psc/time/clocks/context_writers.cpp
hle/service/psc/time/clocks/context_writers.h
hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
hle/service/psc/time/clocks/standard_local_system_clock_core.h
hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
hle/service/psc/time/clocks/standard_network_system_clock_core.h
hle/service/psc/time/clocks/standard_steady_clock_core.cpp
hle/service/psc/time/clocks/standard_steady_clock_core.h
hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
hle/service/psc/time/clocks/standard_user_system_clock_core.h
hle/service/psc/time/clocks/steady_clock_core.h
hle/service/psc/time/clocks/system_clock_core.cpp
hle/service/psc/time/clocks/system_clock_core.h
hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
hle/service/psc/time/clocks/tick_based_steady_clock_core.h
hle/service/psc/time/common.cpp
hle/service/psc/time/common.h
hle/service/psc/time/errors.h
hle/service/psc/time/shared_memory.cpp
hle/service/psc/time/shared_memory.h
hle/service/psc/time/static.cpp
hle/service/psc/time/static.h
hle/service/psc/time/manager.h
hle/service/psc/time/power_state_service.cpp
hle/service/psc/time/power_state_service.h
hle/service/psc/time/service_manager.cpp
hle/service/psc/time/service_manager.h
hle/service/psc/time/steady_clock.cpp
hle/service/psc/time/steady_clock.h
hle/service/psc/time/system_clock.cpp
hle/service/psc/time/system_clock.h
hle/service/psc/time/time_zone.cpp
hle/service/psc/time/time_zone.h
hle/service/psc/time/time_zone_service.cpp
hle/service/psc/time/time_zone_service.h
hle/service/psc/time/power_state_request_manager.cpp
hle/service/psc/time/power_state_request_manager.h
hle/service/ptm/psm.cpp hle/service/ptm/psm.cpp
hle/service/ptm/psm.h hle/service/ptm/psm.h
hle/service/ptm/ptm.cpp hle/service/ptm/ptm.cpp
@ -712,24 +770,24 @@ add_library(core STATIC
hle/service/server_manager.h hle/service/server_manager.h
hle/service/service.cpp hle/service/service.cpp
hle/service/service.h hle/service/service.h
hle/service/set/set.cpp
hle/service/set/set.h
hle/service/set/appln_settings.cpp hle/service/set/appln_settings.cpp
hle/service/set/appln_settings.h hle/service/set/appln_settings.h
hle/service/set/device_settings.cpp hle/service/set/device_settings.cpp
hle/service/set/device_settings.h hle/service/set/device_settings.h
hle/service/set/factory_settings_server.cpp
hle/service/set/factory_settings_server.h
hle/service/set/firmware_debug_settings_server.cpp
hle/service/set/firmware_debug_settings_server.h
hle/service/set/private_settings.cpp hle/service/set/private_settings.cpp
hle/service/set/private_settings.h hle/service/set/private_settings.h
hle/service/set/set_cal.cpp
hle/service/set/set_cal.h
hle/service/set/set_fd.cpp
hle/service/set/set_fd.h
hle/service/set/set_sys.cpp
hle/service/set/set_sys.h
hle/service/set/settings.cpp hle/service/set/settings.cpp
hle/service/set/settings.h hle/service/set/settings.h
hle/service/set/settings_server.cpp
hle/service/set/settings_server.h
hle/service/set/system_settings.cpp hle/service/set/system_settings.cpp
hle/service/set/system_settings.h hle/service/set/system_settings.h
hle/service/set/system_settings_server.cpp
hle/service/set/system_settings_server.h
hle/service/sm/sm.cpp hle/service/sm/sm.cpp
hle/service/sm/sm.h hle/service/sm/sm.h
hle/service/sm/sm_controller.cpp hle/service/sm/sm_controller.cpp
@ -755,40 +813,6 @@ add_library(core STATIC
hle/service/ssl/ssl.cpp hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h hle/service/ssl/ssl.h
hle/service/ssl/ssl_backend.h hle/service/ssl/ssl_backend.h
hle/service/time/clock_types.h
hle/service/time/ephemeral_network_system_clock_context_writer.h
hle/service/time/ephemeral_network_system_clock_core.h
hle/service/time/errors.h
hle/service/time/local_system_clock_context_writer.h
hle/service/time/network_system_clock_context_writer.h
hle/service/time/standard_local_system_clock_core.h
hle/service/time/standard_network_system_clock_core.h
hle/service/time/standard_steady_clock_core.cpp
hle/service/time/standard_steady_clock_core.h
hle/service/time/standard_user_system_clock_core.cpp
hle/service/time/standard_user_system_clock_core.h
hle/service/time/steady_clock_core.h
hle/service/time/system_clock_context_update_callback.cpp
hle/service/time/system_clock_context_update_callback.h
hle/service/time/system_clock_core.cpp
hle/service/time/system_clock_core.h
hle/service/time/tick_based_steady_clock_core.cpp
hle/service/time/tick_based_steady_clock_core.h
hle/service/time/time.cpp
hle/service/time/time.h
hle/service/time/time_interface.cpp
hle/service/time/time_interface.h
hle/service/time/time_manager.cpp
hle/service/time/time_manager.h
hle/service/time/time_sharedmemory.cpp
hle/service/time/time_sharedmemory.h
hle/service/time/time_zone_content_manager.cpp
hle/service/time/time_zone_content_manager.h
hle/service/time/time_zone_manager.cpp
hle/service/time/time_zone_manager.h
hle/service/time/time_zone_service.cpp
hle/service/time/time_zone_service.h
hle/service/time/time_zone_types.h
hle/service/usb/usb.cpp hle/service/usb/usb.cpp
hle/service/usb/usb.h hle/service/usb/usb.h
hle/service/vi/display/vi_display.cpp hle/service/vi/display/vi_display.cpp
@ -869,7 +893,7 @@ endif()
create_target_directory_groups(core) create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb) target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
if (MINGW) if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})

View file

@ -40,9 +40,12 @@
#include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/glue/time/static.h"
#include "core/hle/service/psc/time/static.h"
#include "core/hle/service/psc/time/steady_clock.h"
#include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
#include "core/internal_network/network.h" #include "core/internal_network/network.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/memory.h" #include "core/memory.h"
@ -130,8 +133,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl { struct System::Impl {
explicit Impl(System& system) explicit Impl(System& system)
: kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, : kernel{system}, fs_controller{system}, hid_core{}, room_network{},
reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {} cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {}
void Initialize(System& system) { void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>(); device_memory = std::make_unique<Core::DeviceMemory>();
@ -143,7 +146,7 @@ struct System::Impl {
core_timing.SetMulticore(is_multicore); core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); }); core_timing.Initialize([&system]() { system.RegisterHostThread(); });
RefreshTime(); RefreshTime(system);
// Create a default fs if one doesn't already exist. // Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr) { if (virtual_filesystem == nullptr) {
@ -182,7 +185,7 @@ struct System::Impl {
Initialize(system); Initialize(system);
} }
void RefreshTime() { void RefreshTime(System& system) {
const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
const auto current_time = const auto current_time =
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
@ -190,6 +193,32 @@ struct System::Impl {
(Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue() (Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
: current_time) - : current_time) -
current_time; current_time;
if (!system.IsPoweredOn()) {
return;
}
auto static_service_a =
system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:a", true);
auto static_service_s =
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:s", true);
std::shared_ptr<Service::PSC::Time::SystemClock> user_clock;
static_service_a->GetStandardUserSystemClock(user_clock);
std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
static_service_a->GetStandardLocalSystemClock(local_clock);
std::shared_ptr<Service::PSC::Time::SystemClock> network_clock;
static_service_s->GetStandardNetworkSystemClock(network_clock);
const auto new_time = Settings::values.custom_rtc_enabled
? Settings::values.custom_rtc.GetValue()
: current_time;
user_clock->SetCurrentTime(new_time);
local_clock->SetCurrentTime(new_time);
network_clock->SetCurrentTime(new_time);
} }
void Run() { void Run() {
@ -265,9 +294,6 @@ struct System::Impl {
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
services = std::make_unique<Service::Services>(service_manager, system); services = std::make_unique<Service::Services>(service_manager, system);
// Initialize time manager, which must happen after kernel is created
time_manager.Initialize();
is_powered_on = true; is_powered_on = true;
exit_locked = false; exit_locked = false;
exit_requested = false; exit_requested = false;
@ -416,7 +442,6 @@ struct System::Impl {
service_manager.reset(); service_manager.reset();
cheat_engine.reset(); cheat_engine.reset();
telemetry_session.reset(); telemetry_session.reset();
time_manager.Shutdown();
core_timing.ClearPendingEvents(); core_timing.ClearPendingEvents();
app_loader.reset(); app_loader.reset();
audio_core.reset(); audio_core.reset();
@ -532,7 +557,6 @@ struct System::Impl {
/// Service State /// Service State
Service::Glue::ARPManager arp_manager; Service::Glue::ARPManager arp_manager;
Service::Account::ProfileManager profile_manager; Service::Account::ProfileManager profile_manager;
Service::Time::TimeManager time_manager;
/// Service manager /// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager; std::shared_ptr<Service::SM::ServiceManager> service_manager;
@ -910,14 +934,6 @@ const Service::Account::ProfileManager& System::GetProfileManager() const {
return impl->profile_manager; return impl->profile_manager;
} }
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}
const Service::Time::TimeManager& System::GetTimeManager() const {
return impl->time_manager;
}
void System::SetExitLocked(bool locked) { void System::SetExitLocked(bool locked) {
impl->exit_locked = locked; impl->exit_locked = locked;
} }
@ -1029,13 +1045,9 @@ void System::Exit() {
} }
void System::ApplySettings() { void System::ApplySettings() {
impl->RefreshTime(); impl->RefreshTime(*this);
if (IsPoweredOn()) { if (IsPoweredOn()) {
if (Settings::values.custom_rtc_enabled) {
const s64 posix_time{Settings::values.custom_rtc.GetValue()};
GetTimeManager().UpdateLocalSystemClockTime(posix_time);
}
Renderer().RefreshBaseSettings(); Renderer().RefreshBaseSettings();
} }
} }

View file

@ -73,10 +73,6 @@ namespace SM {
class ServiceManager; class ServiceManager;
} // namespace SM } // namespace SM
namespace Time {
class TimeManager;
} // namespace Time
} // namespace Service } // namespace Service
namespace Tegra { namespace Tegra {
@ -381,9 +377,6 @@ public:
[[nodiscard]] Service::Account::ProfileManager& GetProfileManager(); [[nodiscard]] Service::Account::ProfileManager& GetProfileManager();
[[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const; [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const;
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
[[nodiscard]] Core::Debugger& GetDebugger(); [[nodiscard]] Core::Debugger& GetDebugger();
[[nodiscard]] const Core::Debugger& GetDebugger() const; [[nodiscard]] const Core::Debugger& GetDebugger() const;

View file

@ -66,6 +66,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
event_fifo_id = 0; event_fifo_id = 0;
shutting_down = false; shutting_down = false;
cpu_ticks = 0; cpu_ticks = 0;
clock->Reset();
if (is_multicore) { if (is_multicore) {
timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this)); timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this));
} }
@ -157,7 +158,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
} }
} }
for (auto h : to_remove) { for (auto& h : to_remove) {
event_queue.erase(h); event_queue.erase(h);
} }

View file

@ -64,7 +64,7 @@ public:
return [this] { ShutdownThreadFunction(); }; return [this] { ShutdownThreadFunction(); };
} }
void PreemptSingleCore(bool from_running_enviroment = true); void PreemptSingleCore(bool from_running_environment = true);
std::size_t CurrentCore() const { std::size_t CurrentCore() const {
return current_core.load(); return current_core.load();

View file

@ -559,28 +559,28 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>&
} }
constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
{"----- Free -----", Kernel::Svc::MemoryState::Free}, {"----- Free ------", Kernel::Svc::MemoryState::Free},
{"Io ", Kernel::Svc::MemoryState::Io}, {"Io ", Kernel::Svc::MemoryState::Io},
{"Static ", Kernel::Svc::MemoryState::Static}, {"Static ", Kernel::Svc::MemoryState::Static},
{"Code ", Kernel::Svc::MemoryState::Code}, {"Code ", Kernel::Svc::MemoryState::Code},
{"CodeData ", Kernel::Svc::MemoryState::CodeData}, {"CodeData ", Kernel::Svc::MemoryState::CodeData},
{"Normal ", Kernel::Svc::MemoryState::Normal}, {"Normal ", Kernel::Svc::MemoryState::Normal},
{"Shared ", Kernel::Svc::MemoryState::Shared}, {"Shared ", Kernel::Svc::MemoryState::Shared},
{"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, {"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
{"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
{"Ipc ", Kernel::Svc::MemoryState::Ipc}, {"Ipc ", Kernel::Svc::MemoryState::Ipc},
{"Stack ", Kernel::Svc::MemoryState::Stack}, {"Stack ", Kernel::Svc::MemoryState::Stack},
{"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
{"Transfered ", Kernel::Svc::MemoryState::Transfered}, {"Transferred ", Kernel::Svc::MemoryState::Transferred},
{"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred},
{"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, {"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
{"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
{"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
{"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
{"Kernel ", Kernel::Svc::MemoryState::Kernel}, {"Kernel ", Kernel::Svc::MemoryState::Kernel},
{"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
{"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, {"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
{"Coverage ", Kernel::Svc::MemoryState::Coverage}, {"Coverage ", Kernel::Svc::MemoryState::Coverage},
}}; }};
static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {

View file

@ -26,7 +26,7 @@
#include "core/file_sys/vfs_vector.h" #include "core/file_sys/vfs_vector.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/settings_server.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/loader/nso.h" #include "core/loader/nso.h"
#include "core/memory/cheat_engine.h" #include "core/memory/cheat_engine.h"

View file

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

View file

@ -81,12 +81,12 @@ enum class KMemoryState : u32 {
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped,
Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc |
@ -130,8 +130,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09);
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C);
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x055C3C0D);
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x045C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);

View file

@ -486,8 +486,8 @@ KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const {
case Svc::MemoryState::Shared: case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Transfered: case Svc::MemoryState::Transferred:
case Svc::MemoryState::SharedTransfered: case Svc::MemoryState::SharedTransferred:
case Svc::MemoryState::SharedCode: case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut: case Svc::MemoryState::CodeOut:
@ -522,8 +522,8 @@ size_t KPageTableBase::GetRegionSize(Svc::MemoryState state) const {
case Svc::MemoryState::Shared: case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Transfered: case Svc::MemoryState::Transferred:
case Svc::MemoryState::SharedTransfered: case Svc::MemoryState::SharedTransferred:
case Svc::MemoryState::SharedCode: case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut: case Svc::MemoryState::CodeOut:
@ -564,8 +564,8 @@ bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, Svc::MemorySt
case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Stack: case Svc::MemoryState::Stack:
case Svc::MemoryState::ThreadLocal: case Svc::MemoryState::ThreadLocal:
case Svc::MemoryState::Transfered: case Svc::MemoryState::Transferred:
case Svc::MemoryState::SharedTransfered: case Svc::MemoryState::SharedTransferred:
case Svc::MemoryState::SharedCode: case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut: case Svc::MemoryState::CodeOut:

View file

@ -76,8 +76,8 @@ Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPer
// Map the memory. // Map the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered ? KMemoryState::Transferred
: KMemoryState::SharedTransfered; : KMemoryState::SharedTransferred;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
address, *m_page_group, state, KMemoryPermission::UserReadWrite)); address, *m_page_group, state, KMemoryPermission::UserReadWrite));
@ -96,8 +96,8 @@ Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
// Unmap the memory. // Unmap the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered ? KMemoryState::Transferred
: KMemoryState::SharedTransfered; : KMemoryState::SharedTransferred;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
// Mark ourselves as unmapped. // Mark ourselves as unmapped.

View file

@ -90,7 +90,7 @@ Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t add
// Verify that the mapping is in range. // Verify that the mapping is in range.
R_UNLESS(GetCurrentProcess(system.Kernel()) R_UNLESS(GetCurrentProcess(system.Kernel())
.GetPageTable() .GetPageTable()
.CanContain(address, size, KMemoryState::Transfered), .CanContain(address, size, KMemoryState::Transferred),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
// Map the transfer memory. // Map the transfer memory.
@ -117,7 +117,7 @@ Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t a
// Verify that the mapping is in range. // Verify that the mapping is in range.
R_UNLESS(GetCurrentProcess(system.Kernel()) R_UNLESS(GetCurrentProcess(system.Kernel())
.GetPageTable() .GetPageTable()
.CanContain(address, size, KMemoryState::Transfered), .CanContain(address, size, KMemoryState::Transferred),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
// Unmap the transfer memory. // Unmap the transfer memory.

View file

@ -27,8 +27,8 @@ enum class MemoryState : u32 {
Ipc = 0x0A, Ipc = 0x0A,
Stack = 0x0B, Stack = 0x0B,
ThreadLocal = 0x0C, ThreadLocal = 0x0C,
Transfered = 0x0D, Transferred = 0x0D,
SharedTransfered = 0x0E, SharedTransferred = 0x0E,
SharedCode = 0x0F, SharedCode = 0x0F,
Inaccessible = 0x10, Inaccessible = 0x10,
NonSecureIpc = 0x11, NonSecureIpc = 0x11,

View file

@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions {
bool is_system_or_launcher; bool is_system_or_launcher;
bool is_registration_permitted; bool is_registration_permitted;
bool show_skip_button; bool show_skip_button;
bool aditional_select; bool additional_select;
bool show_user_selector; bool show_user_selector;
bool is_unqualified_user_selectable; bool is_unqualified_user_selectable;
}; };

View file

@ -10,8 +10,11 @@
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h" #include "core/hle/service/caps/caps_result.h"
#include "core/hle/service/time/time_manager.h" #include "core/hle/service/psc/time/static.h"
#include "core/hle/service/time/time_zone_content_manager.h" #include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Capture { namespace Service::Capture {
@ -85,7 +88,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
} }
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, s64 start_posix_time, ContentType content_type, s64 start_posix_time,
s64 end_posix_time, u64 aruid) const { s64 end_posix_time, u64 aruid) const {
if (!is_mounted) { if (!is_mounted) {
return ResultIsNotMounted; return ResultIsNotMounted;
@ -94,7 +97,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
std::vector<ApplicationAlbumEntry> album_entries; std::vector<ApplicationAlbumEntry> album_entries;
const auto start_date = ConvertToAlbumDateTime(start_posix_time); const auto start_date = ConvertToAlbumDateTime(start_posix_time);
const auto end_date = ConvertToAlbumDateTime(end_posix_time); const auto end_date = ConvertToAlbumDateTime(end_posix_time);
const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid); const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid);
if (result.IsError()) { if (result.IsError()) {
return result; return result;
@ -113,14 +116,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
} }
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date, ContentType content_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const { AlbumFileDateTime end_date, u64 aruid) const {
if (!is_mounted) { if (!is_mounted) {
return ResultIsNotMounted; return ResultIsNotMounted;
} }
for (auto& [file_id, path] : album_files) { for (auto& [file_id, path] : album_files) {
if (file_id.type != contex_type) { if (file_id.type != content_type) {
continue; continue;
} }
if (file_id.date > start_date) { if (file_id.date > start_date) {
@ -139,7 +142,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en
.hash{}, .hash{},
.datetime = file_id.date, .datetime = file_id.date,
.storage = file_id.storage, .storage = file_id.storage,
.content = contex_type, .content = content_type,
.unknown = 1, .unknown = 1,
}; };
out_entries.push_back(entry); out_entries.push_back(entry);
@ -239,10 +242,15 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
const ApplicationData& app_data, std::span<const u8> image_data, const ApplicationData& app_data, std::span<const u8> image_data,
u64 aruid) { u64 aruid) {
const u64 title_id = system.GetApplicationProcessProgramID(); const u64 title_id = system.GetApplicationProcessProgramID();
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
auto static_service =
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
static_service->GetStandardUserSystemClock(user_clock);
s64 posix_time{}; s64 posix_time{};
Result result = user_clock.GetCurrentTime(system, posix_time); auto result = user_clock->GetCurrentTime(posix_time);
if (result.IsError()) { if (result.IsError()) {
return result; return result;
@ -257,10 +265,14 @@ Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute, const ScreenShotAttribute& attribute,
const AlbumFileId& file_id, const AlbumFileId& file_id,
std::span<const u8> image_data) { std::span<const u8> image_data) {
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); auto static_service =
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
static_service->GetStandardUserSystemClock(user_clock);
s64 posix_time{}; s64 posix_time{};
Result result = user_clock.GetCurrentTime(system, posix_time); auto result = user_clock->GetCurrentTime(posix_time);
if (result.IsError()) { if (result.IsError()) {
return result; return result;
@ -455,19 +467,23 @@ Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const
} }
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
Time::TimeZone::CalendarInfo calendar_date{}; auto static_service =
const auto& time_zone_manager = system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date); std::shared_ptr<Service::PSC::Time::TimeZoneService> timezone_service{};
static_service->GetTimeZoneService(timezone_service);
Service::PSC::Time::CalendarTime calendar_time{};
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time);
return { return {
.year = calendar_date.time.year, .year = calendar_time.year,
.month = calendar_date.time.month, .month = calendar_time.month,
.day = calendar_date.time.day, .day = calendar_time.day,
.hour = calendar_date.time.hour, .hour = calendar_time.hour,
.minute = calendar_date.time.minute, .minute = calendar_time.minute,
.second = calendar_date.time.second, .second = calendar_time.second,
.unique_id = 0, .unique_id = 0,
}; };
} }

View file

@ -45,10 +45,10 @@ public:
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const; u8 flags) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, s64 start_posix_time, s64 end_posix_time, ContentType content_type, s64 start_posix_time, s64 end_posix_time,
u64 aruid) const; u64 aruid) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date, ContentType content_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const; AlbumFileDateTime end_date, u64 aruid) const;
Result GetAutoSavingStorage(bool& out_is_autosaving) const; Result GetAutoSavingStorage(bool& out_is_autosaving) const;
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,

View file

@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
constexpr Result ResultUnknown6(ErrorModule::Capture, 6); constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
constexpr Result ResultUnknown7(ErrorModule::Capture, 7); constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12);
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);

View file

@ -131,7 +131,7 @@ private:
u8 is_favorite; u8 is_favorite;
u8 same_app; u8 same_app;
u8 same_app_played; u8 same_app_played;
u8 arbitary_app_played; u8 arbitrary_app_played;
u64 group_id; u64 group_id;
}; };
static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");

View file

@ -8,6 +8,9 @@
#include "core/hle/service/glue/ectx.h" #include "core/hle/service/glue/ectx.h"
#include "core/hle/service/glue/glue.h" #include "core/hle/service/glue/glue.h"
#include "core/hle/service/glue/notif.h" #include "core/hle/service/glue/notif.h"
#include "core/hle/service/glue/time/manager.h"
#include "core/hle/service/glue/time/static.h"
#include "core/hle/service/psc/time/common.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
namespace Service::Glue { namespace Service::Glue {
@ -31,6 +34,22 @@ void LoopProcess(Core::System& system) {
// Notification Services for application // Notification Services for application
server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system));
// Time
auto time = std::make_shared<Time::TimeManager>(system);
server_manager->RegisterNamedService(
"time:u",
std::make_shared<Time::StaticService>(
system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, time, "time:u"));
server_manager->RegisterNamedService(
"time:a",
std::make_shared<Time::StaticService>(
system, Service::PSC::Time::StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, time, "time:a"));
server_manager->RegisterNamedService(
"time:r",
std::make_shared<Time::StaticService>(
system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, time, "time:r"));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

View file

@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/service/glue/time/alarm_worker.h"
#include "core/hle/service/psc/time/service_manager.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time {
AlarmWorker::AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource)
: m_system{system}, m_ctx{system, "Glue:AlarmWorker"}, m_steady_clock_resource{
steady_clock_resource} {}
AlarmWorker::~AlarmWorker() {
m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
m_ctx.CloseEvent(m_timer_event);
}
void AlarmWorker::Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m) {
m_time_m = std::move(time_m);
m_timer_event = m_ctx.CreateEvent("Glue:AlarmWorker:TimerEvent");
m_timer_timing_event = Core::Timing::CreateEvent(
"Glue:AlarmWorker::AlarmTimer",
[this](s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
m_timer_event->Signal();
return std::nullopt;
});
AttachToClosestAlarmEvent();
}
bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info,
s64& out_time) {
bool is_valid{};
Service::PSC::Time::AlarmInfo alarm_info{};
s64 closest_time{};
auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time);
ASSERT(res == ResultSuccess);
if (is_valid) {
out_alarm_info = alarm_info;
out_time = closest_time;
}
return is_valid;
}
void AlarmWorker::OnPowerStateChanged() {
Service::PSC::Time::AlarmInfo closest_alarm_info{};
s64 closest_time{};
if (!GetClosestAlarmInfo(closest_alarm_info, closest_time)) {
m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
m_timer_event->Clear();
return;
}
if (closest_alarm_info.alert_time <= closest_time) {
m_time_m->CheckAndSignalAlarms();
} else {
auto next_time{closest_alarm_info.alert_time - closest_time};
m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
m_timer_event->Clear();
m_system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds(next_time),
m_timer_timing_event);
}
}
Result AlarmWorker::AttachToClosestAlarmEvent() {
m_time_m->GetClosestAlarmUpdatedEvent(&m_event);
R_SUCCEED();
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/psc/time/common.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class ServiceManager;
}
namespace Service::Glue::Time {
class StandardSteadyClockResource;
class AlarmWorker {
public:
explicit AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource);
~AlarmWorker();
void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m);
Kernel::KEvent& GetEvent() {
return *m_event;
}
Kernel::KEvent& GetTimerEvent() {
return *m_timer_event;
}
void OnPowerStateChanged();
private:
bool GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, s64& out_time);
Result AttachToClosestAlarmEvent();
Core::System& m_system;
KernelHelpers::ServiceContext m_ctx;
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
Kernel::KEvent* m_event{};
Kernel::KEvent* m_timer_event{};
std::shared_ptr<Core::Timing::EventType> m_timer_timing_event;
StandardSteadyClockResource& m_steady_clock_resource;
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/glue/time/file_timestamp_worker.h"
#include "core/hle/service/psc/time/common.h"
#include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h"
namespace Service::Glue::Time {
void FileTimestampWorker::SetFilesystemPosixTime() {
s64 time{};
Service::PSC::Time::CalendarTime calendar_time{};
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess &&
m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) ==
ResultSuccess) {
// TODO IFileSystemProxy::SetCurrentPosixTime
}
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Service::PSC::Time {
class SystemClock;
class TimeZoneService;
} // namespace Service::PSC::Time
namespace Service::Glue::Time {
class FileTimestampWorker {
public:
FileTimestampWorker() = default;
void SetFilesystemPosixTime();
std::shared_ptr<Service::PSC::Time::SystemClock> m_system_clock{};
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone{};
bool m_initialized{};
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,242 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "core/core.h"
#include "core/core_timing.h"
#include "core/file_sys/vfs.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/service/glue/time/manager.h"
#include "core/hle/service/glue/time/time_zone_binary.h"
#include "core/hle/service/psc/time/service_manager.h"
#include "core/hle/service/psc/time/static.h"
#include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time {
namespace {
template <typename T>
T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
const char* category, const char* name) {
std::vector<u8> interval_buf;
auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
ASSERT(res == ResultSuccess);
T v{};
std::memcpy(&v, interval_buf.data(), sizeof(T));
return v;
}
s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
constexpr auto is_leap = [](s32 year) -> bool {
return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
};
constexpr std::array<s32, 12> MonthStartDayOfYear{
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
};
s16 month_s16{calendar.month};
s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) +
((month_s16 * 43) >> 9))};
s8 month_index{static_cast<s8>(calendar.month - 12 * month)};
if (month_index == 0) {
month_index = 12;
}
s32 year{(month + calendar.year) - !month_index};
s32 v8{year >= 0 ? year : year + 3};
s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1];
days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365;
if (month_index <= 2 && is_leap(year)) {
days_since_epoch--;
}
auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll +
calendar.second};
return epoch_s - 62135683200ll;
}
s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) {
Service::PSC::Time::CalendarTime calendar{
.year = GetSettingsItemValue<s16>(set_sys, "time", "standard_user_clock_initial_year"),
.month = 1,
.day = 1,
.hour = 0,
.minute = 0,
.second = 0,
};
return CalendarTimeToEpoch(calendar);
}
} // namespace
TimeManager::TimeManager(Core::System& system)
: m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource,
m_file_timestamp_worker} {
m_time_m =
system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm);
ASSERT(res == ResultSuccess);
m_set_sys =
system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
ResetTimeZoneBinary();
res = MountTimeZoneBinary(system);
ASSERT(res == ResultSuccess);
m_worker.Initialize(m_time_sm, m_set_sys);
res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock);
ASSERT(res == ResultSuccess);
res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone);
ASSERT(res == ResultSuccess);
res = SetupStandardSteadyClockCore();
ASSERT(res == ResultSuccess);
Service::PSC::Time::SystemClockContext user_clock_context{};
res = m_set_sys->GetUserSystemClockContext(user_clock_context);
ASSERT(res == ResultSuccess);
// TODO this clock should initialise with this epoch time, and be updated somewhere else on
// first boot, but I haven't been able to find that point (likely via ntc's auto correct as it's
// defaulted to be enabled), and to get correct times we need to initialise with the current
// time instead.
auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)};
if (user_clock_context == Service::PSC::Time::SystemClockContext{}) {
m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time);
}
res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time);
ASSERT(res == ResultSuccess);
Service::PSC::Time::SystemClockContext network_clock_context{};
res = m_set_sys->GetNetworkSystemClockContext(network_clock_context);
ASSERT(res == ResultSuccess);
auto network_accuracy_m{GetSettingsItemValue<s32>(
m_set_sys, "time", "standard_network_clock_sufficient_accuracy_minutes")};
auto one_minute_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
s64 network_accuracy_ns{network_accuracy_m * one_minute_ns};
res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns);
ASSERT(res == ResultSuccess);
bool is_automatic_correction_enabled{};
res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(is_automatic_correction_enabled);
ASSERT(res == ResultSuccess);
Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{};
res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime(
automatic_correction_time_point);
ASSERT(res == ResultSuccess);
res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point,
is_automatic_correction_enabled);
ASSERT(res == ResultSuccess);
res = m_time_m->SetupEphemeralNetworkSystemClockCore();
ASSERT(res == ResultSuccess);
res = SetupTimeZoneServiceCore();
ASSERT(res == ResultSuccess);
s64 rtc_time_s{};
res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s);
ASSERT(res == ResultSuccess);
// TODO system report "launch"
// "rtc_reset" = m_steady_clock_resource.m_rtc_reset
// "rtc_value" = rtc_time_s
m_worker.StartThread();
m_file_timestamp_worker.m_initialized = true;
s64 system_clock_time{};
if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) ==
ResultSuccess) {
Service::PSC::Time::CalendarTime calendar_time{};
Service::PSC::Time::CalendarAdditionalInfo calendar_additional{};
if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule(
calendar_time, calendar_additional, system_clock_time) == ResultSuccess) {
// TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time,
// calendar_additional.ut_offset)
}
}
}
Result TimeManager::SetupStandardSteadyClockCore() {
Common::UUID external_clock_source_id{};
auto res = m_set_sys->GetExternalSteadyClockSourceId(external_clock_source_id);
ASSERT(res == ResultSuccess);
s64 external_steady_clock_internal_offset_s{};
res = m_set_sys->GetExternalSteadyClockInternalOffset(external_steady_clock_internal_offset_s);
ASSERT(res == ResultSuccess);
auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s *
one_second_ns};
s32 standard_steady_clock_test_offset_m{
GetSettingsItemValue<s32>(m_set_sys, "time", "standard_steady_clock_test_offset_minutes")};
auto one_minute_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns};
auto reset_detected = m_steady_clock_resource.GetResetDetected();
if (reset_detected) {
external_clock_source_id = {};
}
Common::UUID clock_source_id{};
m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id);
if (clock_source_id != external_clock_source_id) {
m_set_sys->SetExternalSteadyClockSourceId(clock_source_id);
}
res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(),
external_steady_clock_internal_offset_ns,
standard_steady_clock_test_offset_ns,
reset_detected);
ASSERT(res == ResultSuccess);
R_SUCCEED();
}
Result TimeManager::SetupTimeZoneServiceCore() {
Service::PSC::Time::LocationName name{};
auto res = m_set_sys->GetDeviceTimeZoneLocationName(name);
ASSERT(res == ResultSuccess);
Service::PSC::Time::SteadyClockTimePoint time_point{};
res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(time_point);
ASSERT(res == ResultSuccess);
auto location_count = GetTimeZoneCount();
Service::PSC::Time::RuleVersion rule_version{};
GetTimeZoneVersion(rule_version);
std::span<const u8> rule_buffer{};
size_t rule_size{};
res = GetTimeZoneRule(rule_buffer, rule_size, name);
ASSERT(res == ResultSuccess);
res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count,
rule_buffer);
ASSERT(res == ResultSuccess);
R_SUCCEED();
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <functional>
#include <string>
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/glue/time/file_timestamp_worker.h"
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
#include "core/hle/service/glue/time/worker.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class ServiceManager;
class StaticService;
} // namespace Service::PSC::Time
namespace Service::Glue::Time {
class TimeManager {
public:
explicit TimeManager(Core::System& system);
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m{};
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{};
StandardSteadyClockResource m_steady_clock_resource;
FileTimestampWorker m_file_timestamp_worker;
TimeWorker m_worker;
private:
Result SetupStandardSteadyClockCore();
Result SetupTimeZoneServiceCore();
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/glue/time/pm_state_change_handler.h"
namespace Service::Glue::Time {
PmStateChangeHandler::PmStateChangeHandler(AlarmWorker& alarm_worker)
: m_alarm_worker{alarm_worker} {
// TODO Initialize IPmModule, dependent on Rtc and Fs
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
namespace Service::Glue::Time {
class AlarmWorker;
class PmStateChangeHandler {
public:
explicit PmStateChangeHandler(AlarmWorker& alarm_worker);
AlarmWorker& m_alarm_worker;
s32 m_priority{};
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,123 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
#include "core/hle/service/psc/time/errors.h"
namespace Service::Glue::Time {
namespace {
[[maybe_unused]] constexpr u32 Max77620PmicSession = 0x3A000001;
[[maybe_unused]] constexpr u32 Max77620RtcSession = 0x3B000001;
Result GetTimeInSeconds(Core::System& system, s64& out_time_s) {
if (Settings::values.custom_rtc_enabled) {
out_time_s = Settings::values.custom_rtc.GetValue();
} else {
out_time_s = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
}
R_SUCCEED();
}
} // namespace
StandardSteadyClockResource::StandardSteadyClockResource(Core::System& system) : m_system{system} {}
void StandardSteadyClockResource::Initialize(Common::UUID* out_source_id,
Common::UUID* external_source_id) {
constexpr size_t NUM_TRIES{20};
size_t i{0};
Result res{ResultSuccess};
for (; i < NUM_TRIES; i++) {
res = SetCurrentTime();
if (res == ResultSuccess) {
break;
}
Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::milliseconds(1))
.count());
}
if (i < NUM_TRIES) {
m_set_time_result = ResultSuccess;
if (*external_source_id != Service::PSC::Time::ClockSourceId{}) {
m_clock_source_id = *external_source_id;
} else {
m_clock_source_id = Common::UUID::MakeRandom();
}
} else {
m_set_time_result = res;
auto ticks{m_system.CoreTiming().GetClockTicks()};
m_time = -Service::PSC::Time::ConvertToTimeSpan(ticks).count();
m_clock_source_id = Common::UUID::MakeRandom();
}
if (out_source_id) {
*out_source_id = m_clock_source_id;
}
}
bool StandardSteadyClockResource::GetResetDetected() {
// TODO:
// call Rtc::GetRtcResetDetected(Max77620RtcSession)
// if detected:
// SetSys::SetExternalSteadyClockSourceId(invalid_id)
// Rtc::ClearRtcResetDetected(Max77620RtcSession)
// set m_rtc_reset to result
// Instead, only set reset to true if we're booting for the first time.
m_rtc_reset = false;
return m_rtc_reset;
}
Result StandardSteadyClockResource::SetCurrentTime() {
auto start_tick{m_system.CoreTiming().GetClockTicks()};
s64 rtc_time_s{};
// TODO R_TRY(Rtc::GetTimeInSeconds(rtc_time_s, Max77620RtcSession))
R_TRY(GetTimeInSeconds(m_system, rtc_time_s));
auto end_tick{m_system.CoreTiming().GetClockTicks()};
auto diff{Service::PSC::Time::ConvertToTimeSpan(end_tick - start_tick)};
// Why is this here?
R_UNLESS(diff < std::chrono::milliseconds(101), Service::PSC::Time::ResultRtcTimeout);
auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
s64 boot_time{rtc_time_s * one_second_ns -
Service::PSC::Time::ConvertToTimeSpan(end_tick).count()};
std::scoped_lock l{m_mutex};
m_time = boot_time;
R_SUCCEED();
}
Result StandardSteadyClockResource::GetRtcTimeInSeconds(s64& out_time) {
// TODO
// R_TRY(Rtc::GetTimeInSeconds(time_s, Max77620RtcSession)
R_RETURN(GetTimeInSeconds(m_system, out_time));
}
void StandardSteadyClockResource::UpdateTime() {
constexpr size_t NUM_TRIES{3};
size_t i{0};
Result res{ResultSuccess};
for (; i < NUM_TRIES; i++) {
res = SetCurrentTime();
if (res == ResultSuccess) {
break;
}
Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::milliseconds(1))
.count());
}
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/psc/time/common.h"
namespace Core {
class System;
}
namespace Service::Glue::Time {
class StandardSteadyClockResource {
public:
StandardSteadyClockResource(Core::System& system);
void Initialize(Common::UUID* out_source_id, Common::UUID* external_source_id);
s64 GetTime() const {
return m_time;
}
bool GetResetDetected();
Result SetCurrentTime();
Result GetRtcTimeInSeconds(s64& out_time);
void UpdateTime();
private:
Core::System& m_system;
std::mutex m_mutex;
Service::PSC::Time::ClockSourceId m_clock_source_id{};
s64 m_time{};
Result m_set_time_result;
bool m_rtc_reset;
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,447 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "core/core.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/service/glue/time/file_timestamp_worker.h"
#include "core/hle/service/glue/time/static.h"
#include "core/hle/service/psc/time/errors.h"
#include "core/hle/service/psc/time/service_manager.h"
#include "core/hle/service/psc/time/static.h"
#include "core/hle/service/psc/time/steady_clock.h"
#include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time {
namespace {
template <typename T>
T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
const char* category, const char* name) {
std::vector<u8> interval_buf;
auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
ASSERT(res == ResultSuccess);
T v{};
std::memcpy(&v, interval_buf.data(), sizeof(T));
return v;
}
} // namespace
StaticService::StaticService(Core::System& system_,
Service::PSC::Time::StaticServiceSetupInfo setup_info,
std::shared_ptr<TimeManager> time, const char* name)
: ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m},
m_setup_info{setup_info}, m_time_sm{time->m_time_sm},
m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{
time->m_steady_clock_resource} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"},
{1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
{2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"},
{3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"},
{4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
{5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"},
{20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"},
{51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"},
{100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
{101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"},
{200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
{201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
{300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
{400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"},
{401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
{500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
{501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"},
};
// clang-format on
RegisterHandlers(functions);
m_set_sys =
m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock &&
!m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location &&
!m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
m_time_m->GetStaticServiceAsAdmin(m_wrapped_service);
} else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
!m_setup_info.can_write_network_clock &&
!m_setup_info.can_write_timezone_device_location &&
!m_setup_info.can_write_steady_clock &&
!m_setup_info.can_write_uninitialized_clock) {
m_time_m->GetStaticServiceAsUser(m_wrapped_service);
} else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
!m_setup_info.can_write_network_clock &&
!m_setup_info.can_write_timezone_device_location &&
m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
m_time_m->GetStaticServiceAsRepair(m_wrapped_service);
} else {
UNREACHABLE();
}
auto res = m_wrapped_service->GetTimeZoneService(m_time_zone);
ASSERT(res == ResultSuccess);
}
void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
auto res = GetStandardUserSystemClock(service);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
}
void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
auto res = GetStandardNetworkSystemClock(service);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
}
void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
std::shared_ptr<Service::PSC::Time::SteadyClock> service{};
auto res = GetStandardSteadyClock(service);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface(std::move(service));
}
void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
std::shared_ptr<TimeZoneService> service{};
auto res = GetTimeZoneService(service);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface(std::move(service));
}
void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
auto res = GetStandardLocalSystemClock(service);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
}
void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
auto res = GetEphemeralNetworkSystemClock(service);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(res);
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
}
void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Kernel::KSharedMemory* shared_memory{};
auto res = GetSharedMemoryNativeHandle(&shared_memory);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(res);
rb.PushCopyObjects(shared_memory);
}
void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto offset_ns{rp.Pop<s64>()};
auto res = SetStandardSteadyClockInternalOffset(offset_ns);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
s64 rtc_value{};
auto res = GetStandardSteadyClockRtcValue(rtc_value);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.Push(rtc_value);
}
void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
bool is_enabled{};
auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push<bool>(is_enabled);
}
void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto automatic_correction{rp.Pop<bool>()};
auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
s32 initial_year{};
auto res = GetStandardUserSystemClockInitialYear(initial_year);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push(initial_year);
}
void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
bool is_sufficient{};
auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push<bool>(is_sufficient);
}
void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Service::PSC::Time::SteadyClockTimePoint time_point{};
auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
IPC::ResponseBuilder rb{ctx,
2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)};
rb.Push(res);
rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
}
void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
s64 time{};
auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.Push<s64>(time);
}
void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto type{rp.PopEnum<Service::PSC::Time::TimeType>()};
Service::PSC::Time::ClockSnapshot snapshot{};
auto res = GetClockSnapshot(snapshot, type);
ctx.WriteBuffer(snapshot);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()};
Service::PSC::Time::ClockSnapshot snapshot{};
auto res =
GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
ctx.WriteBuffer(snapshot);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser(
HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Service::PSC::Time::ClockSnapshot a{};
Service::PSC::Time::ClockSnapshot b{};
auto a_buffer{ctx.ReadBuffer(0)};
auto b_buffer{ctx.ReadBuffer(1)};
std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
s64 difference{};
auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.Push(difference);
}
void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Service::PSC::Time::ClockSnapshot a{};
Service::PSC::Time::ClockSnapshot b{};
auto a_buffer{ctx.ReadBuffer(0)};
auto b_buffer{ctx.ReadBuffer(1)};
std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
s64 time{};
auto res = CalculateSpanBetween(time, a, b);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(res);
rb.Push(time);
}
// =============================== Implementations ===========================
Result StaticService::GetStandardUserSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service));
}
Result StaticService::GetStandardNetworkSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service));
}
Result StaticService::GetStandardSteadyClock(
std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) {
R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service));
}
Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) {
out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker,
m_setup_info.can_write_timezone_device_location,
m_time_zone);
R_SUCCEED();
}
Result StaticService::GetStandardLocalSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service));
}
Result StaticService::GetEphemeralNetworkSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service));
}
Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) {
R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory));
}
Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied);
R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset(
offset_ns /
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()));
}
Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) {
R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value));
}
Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
bool& out_automatic_correction) {
R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
out_automatic_correction));
}
Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
bool automatic_correction) {
R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled(
automatic_correction));
}
Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) {
out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year");
R_SUCCEED();
}
Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) {
R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
}
Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Service::PSC::Time::SteadyClockTimePoint& out_time_point) {
R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
out_time_point));
}
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
s64& out_time, Service::PSC::Time::SystemClockContext& context) {
R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
}
Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot,
Service::PSC::Time::TimeType type) {
R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
}
Result StaticService::GetClockSnapshotFromSystemClockContext(
Service::PSC::Time::ClockSnapshot& out_snapshot,
Service::PSC::Time::SystemClockContext& user_context,
Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) {
R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context,
network_context, type));
}
Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(
s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) {
R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
}
Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
Service::PSC::Time::ClockSnapshot& b) {
R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/hle/service/glue/time/manager.h"
#include "core/hle/service/glue/time/time_zone.h"
#include "core/hle/service/psc/time/common.h"
namespace Core {
class System;
}
namespace Service::Set {
class ISystemSettingsServer;
}
namespace Service::PSC::Time {
class StaticService;
class SystemClock;
class SteadyClock;
class TimeZoneService;
class ServiceManager;
} // namespace Service::PSC::Time
namespace Service::Glue::Time {
class FileTimestampWorker;
class StandardSteadyClockResource;
class StaticService final : public ServiceFramework<StaticService> {
public:
explicit StaticService(Core::System& system,
Service::PSC::Time::StaticServiceSetupInfo setup_info,
std::shared_ptr<TimeManager> time, const char* name);
~StaticService() override = default;
Result GetStandardUserSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
Result GetStandardNetworkSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service);
Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service);
Result GetStandardLocalSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
Result GetEphemeralNetworkSystemClock(
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory);
Result SetStandardSteadyClockInternalOffset(s64 offset);
Result GetStandardSteadyClockRtcValue(s64& out_rtc_value);
Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction);
Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
Result GetStandardUserSystemClockInitialYear(s32& out_year);
Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient);
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Service::PSC::Time::SteadyClockTimePoint& out_time_point);
Result CalculateMonotonicSystemClockBaseTimePoint(
s64& out_time, Service::PSC::Time::SystemClockContext& context);
Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot,
Service::PSC::Time::TimeType type);
Result GetClockSnapshotFromSystemClockContext(
Service::PSC::Time::ClockSnapshot& out_snapshot,
Service::PSC::Time::SystemClockContext& user_context,
Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type);
Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time,
Service::PSC::Time::ClockSnapshot& a,
Service::PSC::Time::ClockSnapshot& b);
Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
Service::PSC::Time::ClockSnapshot& b);
private:
Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot,
Service::PSC::Time::SystemClockContext& user_context,
Service::PSC::Time::SystemClockContext& network_context,
Service::PSC::Time::TimeType type);
void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
void Handle_GetTimeZoneService(HLERequestContext& ctx);
void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
void Handle_GetClockSnapshot(HLERequestContext& ctx);
void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
void Handle_CalculateSpanBetween(HLERequestContext& ctx);
Core::System& m_system;
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
std::shared_ptr<Service::PSC::Time::StaticService> m_wrapped_service;
Service::PSC::Time::StaticServiceSetupInfo m_setup_info;
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone;
FileTimestampWorker& m_file_timestamp_worker;
StandardSteadyClockResource& m_standard_steady_clock_resource;
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,377 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "core/core.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/service/glue/time/file_timestamp_worker.h"
#include "core/hle/service/glue/time/time_zone.h"
#include "core/hle/service/glue/time/time_zone_binary.h"
#include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time {
namespace {
static std::mutex g_list_mutex;
static Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType g_list_nodes{};
} // namespace
TimeZoneService::TimeZoneService(
Core::System& system_, FileTimestampWorker& file_timestamp_worker,
bool can_write_timezone_device_location,
std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service)
: ServiceFramework{system_, "ITimeZoneService"}, m_system{system},
m_can_write_timezone_device_location{can_write_timezone_device_location},
m_file_timestamp_worker{file_timestamp_worker},
m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"},
{1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"},
{2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"},
{3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"},
{4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
{6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"},
{7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"},
{8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"},
{20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"},
{100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"},
{101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"},
{202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
// clang-format on
RegisterHandlers(functions);
g_list_nodes.clear();
m_set_sys =
m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
}
TimeZoneService::~TimeZoneService() = default;
void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Service::PSC::Time::LocationName name{};
auto res = GetDeviceLocationName(name);
IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)};
rb.Push(res);
rb.PushRaw<Service::PSC::Time::LocationName>(name);
}
void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
auto res = SetDeviceLocation(name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
u32 count{};
auto res = GetTotalLocationNameCount(count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push(count);
}
void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto index{rp.Pop<u32>()};
auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)};
std::vector<Service::PSC::Time::LocationName> names{};
u32 count{};
auto res = LoadLocationNameList(count, names, max_names, index);
ctx.WriteBuffer(names);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push(count);
}
void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
Tz::Rule rule{};
auto res = LoadTimeZoneRule(rule, name);
ctx.WriteBuffer(rule);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Service::PSC::Time::RuleVersion rule_version{};
auto res = GetTimeZoneRuleVersion(rule_version);
IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)};
rb.Push(res);
rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version);
}
void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Service::PSC::Time::LocationName name{};
Service::PSC::Time::SteadyClockTimePoint time_point{};
auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
IPC::ResponseBuilder rb{ctx,
2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) +
(sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))};
rb.Push(res);
rb.PushRaw<Service::PSC::Time::LocationName>(name);
rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
}
void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
auto res = SetDeviceLocationNameWithTimeZoneRule();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(Service::PSC::Time::ResultNotImplemented);
}
void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle(
HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
Kernel::KEvent* event{};
auto res = GetDeviceLocationNameOperationEventReadableHandle(&event);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(res);
rb.PushCopyObjects(event->GetReadableEvent());
}
void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto time{rp.Pop<s64>()};
auto rule_buffer{ctx.ReadBuffer()};
Tz::Rule rule{};
std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
Service::PSC::Time::CalendarTime calendar_time{};
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
IPC::ResponseBuilder rb{ctx,
2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
(sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
rb.Push(res);
rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
}
void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto time{rp.Pop<s64>()};
LOG_DEBUG(Service_Time, "called. time={}", time);
Service::PSC::Time::CalendarTime calendar_time{};
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
IPC::ResponseBuilder rb{ctx,
2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
(sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
rb.Push(res);
rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
}
void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}",
calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute,
calendar.second);
auto binary{ctx.ReadBuffer()};
Tz::Rule rule{};
std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
u32 count{};
std::array<s64, 2> times{};
u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
auto res = ToPosixTime(count, times, times_count, calendar, rule);
ctx.WriteBuffer(times);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push(count);
}
void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
u32 count{};
std::array<s64, 2> times{};
u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
ctx.WriteBuffer(times);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push(count);
}
// =============================== Implementations ===========================
Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) {
R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
}
Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) {
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound);
std::scoped_lock l{m_mutex};
std::span<const u8> binary{};
size_t binary_size{};
R_TRY(GetTimeZoneRule(binary, binary_size, location_name))
R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary));
m_file_timestamp_worker.SetFilesystemPosixTime();
Service::PSC::Time::SteadyClockTimePoint time_point{};
Service::PSC::Time::LocationName name{};
R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name));
m_set_sys->SetDeviceTimeZoneLocationName(name);
m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point);
std::scoped_lock m{g_list_mutex};
for (auto& operation_event : g_list_nodes) {
operation_event.m_event->Signal();
}
R_SUCCEED();
}
Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) {
R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
}
Result TimeZoneService::LoadLocationNameList(
u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names,
u32 index) {
std::scoped_lock l{m_mutex};
R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index));
}
Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule,
Service::PSC::Time::LocationName& name) {
std::scoped_lock l{m_mutex};
std::span<const u8> binary{};
size_t binary_size{};
R_TRY(GetTimeZoneRule(binary, binary_size, name))
R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary));
}
Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
}
Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
Service::PSC::Time::SteadyClockTimePoint& out_time_point,
Service::PSC::Time::LocationName& location_name) {
R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name));
}
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() {
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
R_RETURN(Service::PSC::Time::ResultNotImplemented);
}
Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
Kernel::KEvent** out_event) {
if (!operation_event_initialized) {
operation_event_initialized = false;
m_operation_event.m_ctx.CloseEvent(m_operation_event.m_event);
m_operation_event.m_event =
m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent");
operation_event_initialized = true;
std::scoped_lock l{m_mutex};
g_list_nodes.push_back(m_operation_event);
}
*out_event = m_operation_event.m_event;
R_SUCCEED();
}
Result TimeZoneService::ToCalendarTime(
Service::PSC::Time::CalendarTime& out_calendar_time,
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) {
R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
}
Result TimeZoneService::ToCalendarTimeWithMyRule(
Service::PSC::Time::CalendarTime& out_calendar_time,
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) {
R_RETURN(
m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
}
Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times,
u32 out_times_count,
Service::PSC::Time::CalendarTime& calendar_time,
Tz::Rule& rule) {
R_RETURN(
m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule));
}
Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
u32 out_times_count,
Service::PSC::Time::CalendarTime& calendar_time) {
R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count,
calendar_time));
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <mutex>
#include <span>
#include <vector>
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/psc/time/common.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Tz {
struct Rule;
}
namespace Service::Set {
class ISystemSettingsServer;
}
namespace Service::PSC::Time {
class TimeZoneService;
}
namespace Service::Glue::Time {
class FileTimestampWorker;
class TimeZoneService final : public ServiceFramework<TimeZoneService> {
public:
explicit TimeZoneService(
Core::System& system, FileTimestampWorker& file_timestamp_worker,
bool can_write_timezone_device_location,
std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service);
~TimeZoneService() override;
Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name);
Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name);
Result GetTotalLocationNameCount(u32& out_count);
Result LoadLocationNameList(u32& out_count,
std::vector<Service::PSC::Time::LocationName>& out_names,
size_t max_names, u32 index);
Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name);
Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version);
Result GetDeviceLocationNameAndUpdatedTime(
Service::PSC::Time::SteadyClockTimePoint& out_time_point,
Service::PSC::Time::LocationName& location_name);
Result SetDeviceLocationNameWithTimeZoneRule();
Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event);
Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time,
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time,
Tz::Rule& rule);
Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time,
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info,
s64 time);
Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule);
Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
Service::PSC::Time::CalendarTime& calendar_time);
private:
void Handle_GetDeviceLocationName(HLERequestContext& ctx);
void Handle_SetDeviceLocationName(HLERequestContext& ctx);
void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
void Handle_LoadLocationNameList(HLERequestContext& ctx);
void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
void Handle_ToCalendarTime(HLERequestContext& ctx);
void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
void Handle_ToPosixTime(HLERequestContext& ctx);
void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
Core::System& m_system;
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
bool m_can_write_timezone_device_location;
FileTimestampWorker& m_file_timestamp_worker;
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_wrapped_service;
std::mutex m_mutex;
bool operation_event_initialized{};
Service::PSC::Time::OperationEvent m_operation_event;
};
} // namespace Service::Glue::Time

View file

@ -0,0 +1,205 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/time/time_zone_binary.h"
namespace Service::Glue::Time {
namespace {
constexpr u64 TimeZoneBinaryId = 0x10000000000080E;
static FileSys::VirtualDir g_time_zone_binary_romfs{};
static Result g_time_zone_binary_mount_result{ResultUnknown};
static std::vector<u8> g_time_zone_scratch_space(0x2800, 0);
Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size,
std::string_view path) {
R_UNLESS(g_time_zone_binary_mount_result == ResultSuccess, g_time_zone_binary_mount_result);
auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
R_UNLESS(vfs_file, ResultUnknown);
auto file_size{vfs_file->GetSize()};
R_UNLESS(file_size > 0, ResultUnknown);
R_UNLESS(file_size <= out_buffer_size, Service::PSC::Time::ResultFailed);
out_read_size = vfs_file->Read(out_buffer.data(), file_size);
R_UNLESS(out_read_size > 0, ResultUnknown);
R_SUCCEED();
}
} // namespace
void ResetTimeZoneBinary() {
g_time_zone_binary_romfs = {};
g_time_zone_binary_mount_result = ResultUnknown;
g_time_zone_scratch_space.clear();
g_time_zone_scratch_space.resize(0x2800, 0);
}
Result MountTimeZoneBinary(Core::System& system) {
auto& fsc{system.GetFileSystemController()};
std::unique_ptr<FileSys::NCA> nca{};
auto* bis_system = fsc.GetSystemNANDContents();
R_UNLESS(bis_system, ResultUnknown);
nca = bis_system->GetEntry(TimeZoneBinaryId, FileSys::ContentRecordType::Data);
R_UNLESS(nca, ResultUnknown);
g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS());
if (!g_time_zone_binary_romfs) {
g_time_zone_binary_romfs = FileSys::ExtractRomFS(
FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId));
}
R_UNLESS(g_time_zone_binary_romfs, ResultUnknown);
g_time_zone_binary_mount_result = ResultSuccess;
R_SUCCEED();
}
void GetTimeZoneBinaryListPath(std::string& out_path) {
if (g_time_zone_binary_mount_result != ResultSuccess) {
return;
}
// out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary");
out_path = "/binaryList.txt";
}
void GetTimeZoneBinaryVersionPath(std::string& out_path) {
if (g_time_zone_binary_mount_result != ResultSuccess) {
return;
}
// out_path = fmt::format("{}:/version.txt", "TimeZoneBinary");
out_path = "/version.txt";
}
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) {
if (g_time_zone_binary_mount_result != ResultSuccess) {
return;
}
// out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name);
out_path = fmt::format("/zoneinfo/{}", name.name.data());
}
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
std::string path{};
GetTimeZoneZonePath(path, name);
auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
return vfs_file->GetSize() != 0;
}
u32 GetTimeZoneCount() {
std::string path{};
GetTimeZoneBinaryListPath(path);
size_t bytes_read{};
if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) {
return 0;
}
if (bytes_read == 0) {
return 0;
}
auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read);
u32 count{};
for (auto chr : chars) {
if (chr == '\n') {
count++;
}
}
return count;
}
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
std::string path{};
GetTimeZoneBinaryVersionPath(path);
auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version),
sizeof(Service::PSC::Time::RuleVersion))};
size_t bytes_read{};
R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(),
path));
rule_version_buffer[bytes_read] = 0;
R_SUCCEED();
}
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
Service::PSC::Time::LocationName& name) {
std::string path{};
GetTimeZoneZonePath(path, name);
size_t bytes_read{};
R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space,
g_time_zone_scratch_space.size(), path));
out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read);
out_rule_size = bytes_read;
R_SUCCEED();
}
Result GetTimeZoneLocationList(u32& out_count,
std::vector<Service::PSC::Time::LocationName>& out_names,
size_t max_names, u32 index) {
std::string path{};
GetTimeZoneBinaryListPath(path);
size_t bytes_read{};
R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space,
g_time_zone_scratch_space.size(), path));
out_count = 0;
R_SUCCEED_IF(bytes_read == 0);
Service::PSC::Time::LocationName current_name{};
size_t current_name_len{};
std::span<const u8> chars{g_time_zone_scratch_space};
u32 name_count{};
for (auto chr : chars) {
if (chr == '\r') {
continue;
}
if (chr == '\n') {
if (name_count >= index) {
out_names.push_back(current_name);
out_count++;
if (out_count >= max_names) {
break;
}
}
name_count++;
current_name_len = 0;
current_name = {};
continue;
}
if (chr == '\0') {
break;
}
R_UNLESS(current_name_len <= current_name.name.size() - 2,
Service::PSC::Time::ResultFailed);
current_name.name[current_name_len++] = chr;
}
R_SUCCEED();
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include <string>
#include <string_view>
#include "core/hle/service/psc/time/common.h"
namespace Core {
class System;
}
namespace Service::Glue::Time {
void ResetTimeZoneBinary();
Result MountTimeZoneBinary(Core::System& system);
void GetTimeZoneBinaryListPath(std::string& out_path);
void GetTimeZoneBinaryVersionPath(std::string& out_path);
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name);
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name);
u32 GetTimeZoneCount();
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
Service::PSC::Time::LocationName& name);
Result GetTimeZoneLocationList(u32& out_count,
std::vector<Service::PSC::Time::LocationName>& out_names,
size_t max_names, u32 index);
} // namespace Service::Glue::Time

View file

@ -0,0 +1,338 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/service/glue/time/file_timestamp_worker.h"
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
#include "core/hle/service/glue/time/worker.h"
#include "core/hle/service/psc/time/common.h"
#include "core/hle/service/psc/time/service_manager.h"
#include "core/hle/service/psc/time/static.h"
#include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time {
namespace {
bool g_ig_report_network_clock_context_set{};
Service::PSC::Time::SystemClockContext g_report_network_clock_context{};
bool g_ig_report_ephemeral_clock_context_set{};
Service::PSC::Time::SystemClockContext g_report_ephemeral_clock_context{};
template <typename T>
T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
const char* category, const char* name) {
std::vector<u8> interval_buf;
auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
ASSERT(res == ResultSuccess);
T v{};
std::memcpy(&v, interval_buf.data(), sizeof(T));
return v;
}
} // namespace
TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
FileTimestampWorker& file_timestamp_worker)
: m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")},
m_steady_clock_resource{steady_clock_resource},
m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent(
"Glue:58:SteadyClockTimerEvent")},
m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")},
m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} {
g_ig_report_network_clock_context_set = false;
g_report_network_clock_context = {};
g_ig_report_ephemeral_clock_context_set = false;
g_report_ephemeral_clock_context = {};
m_timer_steady_clock_timing_event = Core::Timing::CreateEvent(
"Time::SteadyClockEvent",
[this](s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
m_timer_steady_clock->Signal();
return std::nullopt;
});
m_timer_file_system_timing_event = Core::Timing::CreateEvent(
"Time::SteadyClockEvent",
[this](s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
m_timer_file_system->Signal();
return std::nullopt;
});
}
TimeWorker::~TimeWorker() {
m_local_clock_event->Signal();
m_network_clock_event->Signal();
m_ephemeral_clock_event->Signal();
std::this_thread::sleep_for(std::chrono::milliseconds(16));
m_thread.request_stop();
m_event->Signal();
m_thread.join();
m_ctx.CloseEvent(m_event);
m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event);
m_ctx.CloseEvent(m_timer_steady_clock);
m_system.CoreTiming().UnscheduleEvent(m_timer_file_system_timing_event);
m_ctx.CloseEvent(m_timer_file_system);
}
void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) {
m_set_sys = std::move(set_sys);
m_time_m =
m_system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
m_time_sm = std::move(time_sm);
m_alarm_worker.Initialize(m_time_m);
auto steady_clock_interval_m = GetSettingsItemValue<s32>(
m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes");
auto one_minute_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
s64 steady_clock_interval_ns{steady_clock_interval_m * one_minute_ns};
m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
std::chrono::nanoseconds(steady_clock_interval_ns),
m_timer_steady_clock_timing_event);
auto fs_notify_time_s =
GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds");
auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns};
m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
std::chrono::nanoseconds(fs_notify_time_ns),
m_timer_file_system_timing_event);
auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock);
ASSERT(res == ResultSuccess);
res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event);
ASSERT(res == ResultSuccess);
res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock);
ASSERT(res == ResultSuccess);
res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event);
ASSERT(res == ResultSuccess);
res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock);
ASSERT(res == ResultSuccess);
res =
m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event);
ASSERT(res == ResultSuccess);
res = m_time_m->GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
&m_standard_user_auto_correct_clock_event);
ASSERT(res == ResultSuccess);
}
void TimeWorker::StartThread() {
m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this));
}
void TimeWorker::ThreadFunc(std::stop_token stop_token) {
Common::SetCurrentThreadName("TimeWorker");
Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
enum class EventType {
Exit = 0,
IpmModuleService_GetEvent = 1,
PowerStateChange = 2,
SignalAlarms = 3,
UpdateLocalSystemClock = 4,
UpdateNetworkSystemClock = 5,
UpdateEphemeralSystemClock = 6,
UpdateSteadyClock = 7,
UpdateFileTimestamp = 8,
AutoCorrect = 9,
Max = 10,
};
s32 num_objs{};
std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{};
std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{};
const auto AddWaiter{
[&](Kernel::KSynchronizationObject* synchronization_object, EventType type) {
// Open a new reference to the object.
synchronization_object->Open();
// Insert into the list.
wait_indices[num_objs] = type;
wait_objs[num_objs++] = synchronization_object;
}};
while (!stop_token.stop_requested()) {
SCOPE_EXIT({
for (s32 i = 0; i < num_objs; i++) {
wait_objs[i]->Close();
}
});
num_objs = {};
wait_objs = {};
if (m_pm_state_change_handler.m_priority != 0) {
AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
// TODO
// AddWaiter(gIPmModuleService::GetEvent(), 1);
AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange);
} else {
AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
// TODO
// AddWaiter(gIPmModuleService::GetEvent(), 1);
AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange);
AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms);
AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock);
AddWaiter(&m_network_clock_event->GetReadableEvent(),
EventType::UpdateNetworkSystemClock);
AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(),
EventType::UpdateEphemeralSystemClock);
AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock);
AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp);
AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(),
EventType::AutoCorrect);
}
s32 out_index{-1};
Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
num_objs, -1);
ASSERT(out_index >= 0 && out_index < num_objs);
if (stop_token.stop_requested()) {
return;
}
switch (wait_indices[out_index]) {
case EventType::Exit:
return;
case EventType::IpmModuleService_GetEvent:
// TODO
// IPmModuleService::GetEvent()
// clear the event
// Handle power state change event
break;
case EventType::PowerStateChange:
m_alarm_worker.GetEvent().Clear();
if (m_pm_state_change_handler.m_priority <= 1) {
m_alarm_worker.OnPowerStateChanged();
}
break;
case EventType::SignalAlarms:
m_alarm_worker.GetTimerEvent().Clear();
m_time_m->CheckAndSignalAlarms();
break;
case EventType::UpdateLocalSystemClock: {
m_local_clock_event->Clear();
Service::PSC::Time::SystemClockContext context{};
auto res = m_local_clock->GetSystemClockContext(context);
ASSERT(res == ResultSuccess);
m_set_sys->SetUserSystemClockContext(context);
m_file_timestamp_worker.SetFilesystemPosixTime();
} break;
case EventType::UpdateNetworkSystemClock: {
m_network_clock_event->Clear();
Service::PSC::Time::SystemClockContext context{};
auto res = m_network_clock->GetSystemClockContext(context);
ASSERT(res == ResultSuccess);
m_set_sys->SetNetworkSystemClockContext(context);
s64 time{};
if (m_network_clock->GetCurrentTime(time) != ResultSuccess) {
break;
}
[[maybe_unused]] auto offset_before{
g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0};
// TODO system report "standard_netclock_operation"
// "clock_time" = time
// "context_offset_before" = offset_before
// "context_offset_after" = context.offset
g_report_network_clock_context = context;
if (!g_ig_report_network_clock_context_set) {
g_ig_report_network_clock_context_set = true;
}
m_file_timestamp_worker.SetFilesystemPosixTime();
} break;
case EventType::UpdateEphemeralSystemClock: {
m_ephemeral_clock_event->Clear();
Service::PSC::Time::SystemClockContext context{};
auto res = m_ephemeral_clock->GetSystemClockContext(context);
if (res != ResultSuccess) {
break;
}
s64 time{};
res = m_ephemeral_clock->GetCurrentTime(time);
if (res != ResultSuccess) {
break;
}
[[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set
? g_report_ephemeral_clock_context.offset
: 0};
// TODO system report "ephemeral_netclock_operation"
// "clock_time" = time
// "context_offset_before" = offset_before
// "context_offset_after" = context.offset
g_report_ephemeral_clock_context = context;
if (!g_ig_report_ephemeral_clock_context_set) {
g_ig_report_ephemeral_clock_context_set = true;
}
} break;
case EventType::UpdateSteadyClock:
m_timer_steady_clock->Clear();
m_steady_clock_resource.UpdateTime();
m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime());
break;
case EventType::UpdateFileTimestamp:
m_timer_file_system->Clear();
m_file_timestamp_worker.SetFilesystemPosixTime();
break;
case EventType::AutoCorrect: {
m_standard_user_auto_correct_clock_event->Clear();
bool automatic_correction{};
auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
automatic_correction);
ASSERT(res == ResultSuccess);
Service::PSC::Time::SteadyClockTimePoint time_point{};
res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
ASSERT(res == ResultSuccess);
m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
} break;
default:
UNREACHABLE();
break;
}
}
}
} // namespace Service::Glue::Time

View file

@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/glue/time/alarm_worker.h"
#include "core/hle/service/glue/time/pm_state_change_handler.h"
#include "core/hle/service/kernel_helpers.h"
namespace Service::Set {
class ISystemSettingsServer;
}
namespace Service::PSC::Time {
class StaticService;
class SystemClock;
} // namespace Service::PSC::Time
namespace Service::Glue::Time {
class FileTimestampWorker;
class StandardSteadyClockResource;
class TimeWorker {
public:
explicit TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
FileTimestampWorker& file_timestamp_worker);
~TimeWorker();
void Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys);
void StartThread();
private:
void ThreadFunc(std::stop_token stop_token);
Core::System& m_system;
KernelHelpers::ServiceContext m_ctx;
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
std::jthread m_thread;
Kernel::KEvent* m_event{};
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
std::shared_ptr<Service::PSC::Time::SystemClock> m_network_clock;
std::shared_ptr<Service::PSC::Time::SystemClock> m_local_clock;
std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock;
StandardSteadyClockResource& m_steady_clock_resource;
FileTimestampWorker& m_file_timestamp_worker;
Kernel::KEvent* m_local_clock_event{};
Kernel::KEvent* m_network_clock_event{};
Kernel::KEvent* m_ephemeral_clock_event{};
Kernel::KEvent* m_standard_user_auto_correct_clock_event{};
Kernel::KEvent* m_timer_steady_clock{};
std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event;
Kernel::KEvent* m_timer_file_system{};
std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event;
AlarmWorker m_alarm_worker;
PmStateChangeHandler m_pm_state_change_handler;
};
} // namespace Service::Glue::Time

View file

@ -18,23 +18,23 @@ namespace Service::HID {
void LoopProcess(Core::System& system) { void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system); auto server_manager = std::make_unique<ServerManager>(system);
std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system); std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);
std::shared_ptr<HidFirmwareSettings> firmware_settings = std::shared_ptr<HidFirmwareSettings> firmware_settings =
std::make_shared<HidFirmwareSettings>(); std::make_shared<HidFirmwareSettings>();
// TODO: Remove this hack until this service is emulated properly. // TODO: Remove this hack until this service is emulated properly.
const auto process_list = system.Kernel().GetProcessList(); const auto process_list = system.Kernel().GetProcessList();
if (!process_list.empty()) { if (!process_list.empty()) {
resouce_manager->Initialize(); resource_manager->Initialize();
resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
} }
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager)); "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager));
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager)); "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager));
server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));

View file

@ -1444,8 +1444,8 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, "(STUBBED) called, use_center_clamp={}, applet_resource_user_id={}", LOG_INFO(Service_HID, "called, use_center_clamp={}, applet_resource_user_id={}",
parameters.use_center_clamp, parameters.applet_resource_user_id); parameters.use_center_clamp, parameters.applet_resource_user_id);
GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp( GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp(
parameters.applet_resource_user_id, parameters.use_center_clamp); parameters.applet_resource_user_id, parameters.use_center_clamp);
@ -1466,23 +1466,27 @@ void IHidServer::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, LOG_INFO(Service_HID, "called, npad_styleset={}, applet_resource_user_id={}, button={}",
"(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}", parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
const auto result = GetResourceManager()->GetNpad()->SetNpadCaptureButtonAssignment(
parameters.applet_resource_user_id, parameters.npad_styleset, parameters.button);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(result);
} }
void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) { void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
applet_resource_user_id);
const auto result =
GetResourceManager()->GetNpad()->ClearNpadCaptureButtonAssignment(applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(result);
} }
void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {

View file

@ -46,7 +46,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"}, {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
{312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"}, {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
{313, nullptr, "GetNpadCaptureButtonAssignment"}, {313, &IHidSystemServer::GetNpadCaptureButtonAssignment, "GetNpadCaptureButtonAssignment"},
{314, nullptr, "GetAppletFooterUiType"}, {314, nullptr, "GetAppletFooterUiType"},
{315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"}, {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
{316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"}, {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
@ -54,8 +54,8 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{318, &IHidSystemServer::HasBattery, "HasBattery"}, {318, &IHidSystemServer::HasBattery, "HasBattery"},
{319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"}, {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
{321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
{322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"}, {322, &IHidSystemServer::SetNpadSystemExtStateEnabled, "SetNpadSystemExtStateEnabled"},
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, {323, nullptr, "GetLastActiveUniquePad"},
{324, nullptr, "GetUniquePadButtonSet"}, {324, nullptr, "GetUniquePadButtonSet"},
{325, nullptr, "GetUniquePadColor"}, {325, nullptr, "GetUniquePadColor"},
{326, nullptr, "GetUniquePadAppletDetailedUiType"}, {326, nullptr, "GetUniquePadAppletDetailedUiType"},
@ -251,25 +251,38 @@ void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
} }
void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) { void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called"); IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, true);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) { void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called"); IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, false);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) { void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running Core::HID::NpadIdType npad_id{};
const Result result = GetResourceManager()->GetNpad()->GetLastActiveNpad(npad_id);
LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(result);
rb.Push(0); // Dont forget to fix this rb.PushEnum(npad_id);
} }
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
@ -331,6 +344,27 @@ void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
rb.Push(result); rb.Push(result);
} }
void IHidSystemServer::GetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto capture_button_list_size{ctx.GetWriteBufferNumElements<Core::HID::NpadButton>()};
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
std::vector<Core::HID::NpadButton> capture_button_list(capture_button_list_size);
const auto& npad = GetResourceManager()->GetNpad();
const u64 list_size =
npad->GetNpadCaptureButtonAssignment(capture_button_list, applet_resource_user_id);
if (list_size != 0) {
ctx.WriteBuffer(capture_button_list);
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(list_size);
}
void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()}; const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
@ -423,13 +457,25 @@ void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
rb.Push(static_cast<u32>(unique_pads.size())); rb.Push(static_cast<u32>(unique_pads.size()));
} }
void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) { void IHidSystemServer::SetNpadSystemExtStateEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters {
bool is_enabled;
INSERT_PADDING_BYTES_NOINIT(7);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
LOG_WARNING(Service_HID, "(STUBBED) called"); const auto parameters{rp.PopRaw<Parameters>()};
LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
parameters.is_enabled, parameters.applet_resource_user_id);
const auto result = GetResourceManager()->GetNpad()->SetNpadSystemExtStateEnabled(
parameters.applet_resource_user_id, parameters.is_enabled);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(result);
} }
void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) { void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};

View file

@ -31,13 +31,14 @@ private:
void GetNpadFullKeyGripColor(HLERequestContext& ctx); void GetNpadFullKeyGripColor(HLERequestContext& ctx);
void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx); void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
void SetSupportedNpadStyleSetAll(HLERequestContext& ctx); void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
void GetNpadCaptureButtonAssignment(HLERequestContext& ctx);
void GetAppletDetailedUiType(HLERequestContext& ctx); void GetAppletDetailedUiType(HLERequestContext& ctx);
void GetNpadInterfaceType(HLERequestContext& ctx); void GetNpadInterfaceType(HLERequestContext& ctx);
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx); void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
void HasBattery(HLERequestContext& ctx); void HasBattery(HLERequestContext& ctx);
void HasLeftRightBattery(HLERequestContext& ctx); void HasLeftRightBattery(HLERequestContext& ctx);
void GetUniquePadsFromNpad(HLERequestContext& ctx); void GetUniquePadsFromNpad(HLERequestContext& ctx);
void GetIrSensorState(HLERequestContext& ctx); void SetNpadSystemExtStateEnabled(HLERequestContext& ctx);
void RegisterAppletResourceUserId(HLERequestContext& ctx); void RegisterAppletResourceUserId(HLERequestContext& ctx);
void UnregisterAppletResourceUserId(HLERequestContext& ctx); void UnregisterAppletResourceUserId(HLERequestContext& ctx);
void EnableAppletToGetInput(HLERequestContext& ctx); void EnableAppletToGetInput(HLERequestContext& ctx);

View file

@ -67,7 +67,7 @@ HidBus::~HidBus() {
void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
if (is_hidbus_enabled) { if (is_hidbus_enabled) {
for (std::size_t i = 0; i < devices.size(); ++i) { for (std::size_t i = 0; i < devices.size(); ++i) {
if (!devices[i].is_device_initializated) { if (!devices[i].is_device_initialized) {
continue; continue;
} }
auto& device = devices[i].device; auto& device = devices[i].device;
@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
MakeDevice<RingController>(bus_handle_); MakeDevice<RingController>(bus_handle_);
devices[device_index.value()].is_device_initializated = true; devices[device_index.value()].is_device_initialized = true;
devices[device_index.value()].device->ActivateDevice(); devices[device_index.value()].device->ActivateDevice();
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;
cur_entry.is_connected = true; cur_entry.is_connected = true;
@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
cur_entry.is_polling_mode = false; cur_entry.is_polling_mode = false;
} else { } else {
MakeDevice<HidbusStubbed>(bus_handle_); MakeDevice<HidbusStubbed>(bus_handle_);
devices[device_index.value()].is_device_initializated = true; devices[device_index.value()].is_device_initialized = true;
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;
cur_entry.is_connected = false; cur_entry.is_connected = false;
cur_entry.is_connected_result = ResultSuccess; cur_entry.is_connected_result = ResultSuccess;
@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) {
const auto entry_index = devices[device_index.value()].handle.internal_index; const auto entry_index = devices[device_index.value()].handle.internal_index;
auto& cur_entry = hidbus_status.entries[entry_index]; auto& cur_entry = hidbus_status.entries[entry_index];
auto& device = devices[device_index.value()].device; auto& device = devices[device_index.value()].device;
devices[device_index.value()].is_device_initializated = false; devices[device_index.value()].is_device_initialized = false;
device->DeactivateDevice(); device->DeactivateDevice();
cur_entry.is_in_focus = true; cur_entry.is_in_focus = true;

View file

@ -89,7 +89,7 @@ private:
static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size");
struct HidbusDevice { struct HidbusDevice {
bool is_device_initializated{}; bool is_device_initialized{};
BusHandle handle{}; BusHandle handle{};
std::unique_ptr<HidbusBase> device{nullptr}; std::unique_ptr<HidbusBase> device{nullptr};
}; };

View file

@ -182,22 +182,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
} }
} }
buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors);
buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors);
buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors);
buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors);
for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
} }
for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
} }
for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
} }
for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
} }
const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
@ -247,7 +247,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) {
if (command_header->buf_c_descriptor_flags == if (command_header->buf_c_descriptor_flags ==
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} else { } else {
u32 num_buf_c_descriptors = u32 num_buf_c_descriptors =
static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
@ -257,7 +257,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
ASSERT(num_buf_c_descriptors < 14); ASSERT(num_buf_c_descriptors < 14);
for (u32 i = 0; i < num_buf_c_descriptors; ++i) { for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} }
} }
} }

View file

@ -234,19 +234,19 @@ public:
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const {
return buffer_x_desciptors; return buffer_x_descriptors;
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
return buffer_a_desciptors; return buffer_a_descriptors;
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const {
return buffer_b_desciptors; return buffer_b_descriptors;
} }
[[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
return buffer_c_desciptors; return buffer_c_descriptors;
} }
[[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const {
@ -408,11 +408,11 @@ private:
std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header;
std::optional<IPC::DataPayloadHeader> data_payload_header; std::optional<IPC::DataPayloadHeader> data_payload_header;
std::optional<IPC::DomainMessageHeader> domain_message_header; std::optional<IPC::DomainMessageHeader> domain_message_header;
std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; std::vector<IPC::BufferDescriptorX> buffer_x_descriptors;
std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors;
std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors;
std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors;
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; std::vector<IPC::BufferDescriptorC> buffer_c_descriptors;
u32_le command{}; u32_le command{};
u64 pid{}; u64 pid{};

View file

@ -65,6 +65,9 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
} }
void ServiceContext::CloseEvent(Kernel::KEvent* event) { void ServiceContext::CloseEvent(Kernel::KEvent* event) {
if (!event) {
return;
}
event->GetReadableEvent().Close(); event->GetReadableEvent().Close();
event->Close(); event->Close();
} }

View file

@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto {
bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
const auto& amiibo_data = ntag_file.user_memory; const auto& amiibo_data = ntag_file.user_memory;
LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock);
LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container); LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container);
LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter));
LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id);
@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
if (ntag_file.static_lock != 0xE00F) { if (ntag_file.static_lock != 0xE00F) {
return false; return false;
} }
if (ntag_file.compability_container != 0xEEFF10F1U) { if (ntag_file.compatibility_container != 0xEEFF10F1U) {
return false; return false;
} }
if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
encoded_data.internal_number = nfc_data.internal_number; encoded_data.internal_number = nfc_data.internal_number;
encoded_data.static_lock = nfc_data.static_lock; encoded_data.static_lock = nfc_data.static_lock;
encoded_data.compability_container = nfc_data.compability_container; encoded_data.compatibility_container = nfc_data.compatibility_container;
encoded_data.hmac_data = nfc_data.user_memory.hmac_data; encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
encoded_data.constant_value = nfc_data.user_memory.constant_value; encoded_data.constant_value = nfc_data.user_memory.constant_value;
encoded_data.write_counter = nfc_data.user_memory.write_counter; encoded_data.write_counter = nfc_data.user_memory.write_counter;
@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
nfc_data.internal_number = encoded_data.internal_number; nfc_data.internal_number = encoded_data.internal_number;
nfc_data.static_lock = encoded_data.static_lock; nfc_data.static_lock = encoded_data.static_lock;
nfc_data.compability_container = encoded_data.compability_container; nfc_data.compatibility_container = encoded_data.compatibility_container;
nfc_data.user_memory.hmac_data = encoded_data.hmac_data; nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
nfc_data.user_memory.constant_value = encoded_data.constant_value; nfc_data.user_memory.constant_value = encoded_data.constant_value;
nfc_data.user_memory.write_counter = encoded_data.write_counter; nfc_data.user_memory.write_counter = encoded_data.write_counter;
@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
out_data.uid_crc_check2 = in_data.uid_crc_check2; out_data.uid_crc_check2 = in_data.uid_crc_check2;
out_data.internal_number = in_data.internal_number; out_data.internal_number = in_data.internal_number;
out_data.static_lock = in_data.static_lock; out_data.static_lock = in_data.static_lock;
out_data.compability_container = in_data.compability_container; out_data.compatibility_container = in_data.compatibility_container;
out_data.constant_value = in_data.constant_value; out_data.constant_value = in_data.constant_value;
out_data.write_counter = in_data.write_counter; out_data.write_counter = in_data.write_counter;

View file

@ -29,7 +29,11 @@
#include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/mifare_result.h" #include "core/hle/service/nfc/mifare_result.h"
#include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/time_manager.h" #include "core/hle/service/psc/time/static.h"
#include "core/hle/service/psc/time/steady_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/frontend/emulated_controller.h" #include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h" #include "hid_core/hid_core.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
@ -75,7 +79,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
return; return;
} }
if (!is_initalized) { if (!is_initialized) {
return; return;
} }
@ -207,7 +211,7 @@ void NfcDevice::Initialize() {
return; return;
} }
is_initalized = npad_device->AddNfcHandle(); is_initialized = npad_device->AddNfcHandle();
} }
void NfcDevice::Finalize() { void NfcDevice::Finalize() {
@ -226,7 +230,7 @@ void NfcDevice::Finalize() {
} }
device_state = DeviceState::Unavailable; device_state = DeviceState::Unavailable;
is_initalized = false; is_initialized = false;
} }
Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
@ -393,8 +397,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
return result; return result;
} }
Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, Result NfcDevice::SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data,
std::span<const u8> command_data,
std::span<u8> out_data) { std::span<u8> out_data) {
// Not implemented // Not implemented
return ResultSuccess; return ResultSuccess;
@ -1396,27 +1399,41 @@ void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
} }
NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const { NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
const auto& time_zone_manager = auto static_service =
system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
Time::TimeZone::CalendarInfo calendar_info{};
std::shared_ptr<Service::PSC::Time::TimeZoneService> timezone_service{};
static_service->GetTimeZoneService(timezone_service);
Service::PSC::Time::CalendarTime calendar_time{};
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
NFP::AmiiboDate amiibo_date{}; NFP::AmiiboDate amiibo_date{};
amiibo_date.SetYear(2000); amiibo_date.SetYear(2000);
amiibo_date.SetMonth(1); amiibo_date.SetMonth(1);
amiibo_date.SetDay(1); amiibo_date.SetDay(1);
if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { if (timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time) ==
amiibo_date.SetYear(calendar_info.time.year); ResultSuccess) {
amiibo_date.SetMonth(calendar_info.time.month); amiibo_date.SetYear(calendar_time.year);
amiibo_date.SetDay(calendar_info.time.day); amiibo_date.SetMonth(calendar_time.month);
amiibo_date.SetDay(calendar_time.day);
} }
return amiibo_date; return amiibo_date;
} }
u64 NfcDevice::GetCurrentPosixTime() const { s64 NfcDevice::GetCurrentPosixTime() const {
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; auto static_service =
return standard_steady_clock.GetCurrentTimePoint(system).time_point; system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
static_service->GetStandardSteadyClock(steady_clock);
Service::PSC::Time::SteadyClockTimePoint time_point{};
R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
return time_point.time_point;
} }
u64 NfcDevice::RemoveVersionByte(u64 application_id) const { u64 NfcDevice::RemoveVersionByte(u64 application_id) const {

View file

@ -11,7 +11,6 @@
#include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
namespace Kernel { namespace Kernel {
class KEvent; class KEvent;
@ -49,8 +48,8 @@ public:
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, Result SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data,
std::span<const u8> command_data, std::span<u8> out_data); std::span<u8> out_data);
Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target); Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
Result Unmount(); Result Unmount();
@ -108,7 +107,7 @@ private:
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const; void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const; NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
u64 GetCurrentPosixTime() const; s64 GetCurrentPosixTime() const;
u64 RemoveVersionByte(u64 application_id) const; u64 RemoveVersionByte(u64 application_id) const;
void UpdateSettingsCrc(); void UpdateSettingsCrc();
void UpdateRegisterInfoCrc(); void UpdateRegisterInfoCrc();
@ -126,7 +125,7 @@ private:
Kernel::KEvent* deactivate_event = nullptr; Kernel::KEvent* deactivate_event = nullptr;
Kernel::KEvent* availability_change_event = nullptr; Kernel::KEvent* availability_change_event = nullptr;
bool is_initalized{}; bool is_initialized{};
NfcProtocol allowed_protocols{}; NfcProtocol allowed_protocols{};
DeviceState device_state{DeviceState::Unavailable}; DeviceState device_state{DeviceState::Unavailable};

View file

@ -10,8 +10,10 @@
#include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/common/device_manager.h" #include "core/hle/service/nfc/common/device_manager.h"
#include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/clock_types.h" #include "core/hle/service/psc/time/static.h"
#include "core/hle/service/time/time_manager.h" #include "core/hle/service/psc/time/steady_clock.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
#include "hid_core/hid_util.h" #include "hid_core/hid_util.h"
@ -82,11 +84,19 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max
continue; continue;
} }
if (skip_fatal_errors) { if (skip_fatal_errors) {
constexpr u64 MinimumRecoveryTime = 60; constexpr s64 MinimumRecoveryTime = 60;
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
time_since_last_error;
auto static_service =
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u",
true);
std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
static_service->GetStandardSteadyClock(steady_clock);
Service::PSC::Time::SteadyClockTimePoint time_point{};
R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
const s64 elapsed_time = time_point.time_point - time_since_last_error;
if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
continue; continue;
} }
@ -250,8 +260,7 @@ Result DeviceManager::WriteMifare(u64 device_handle,
return result; return result;
} }
Result DeviceManager::SendCommandByPassThrough(u64 device_handle, Result DeviceManager::SendCommandByPassThrough(u64 device_handle, const s64& timeout,
const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data, std::span<const u8> command_data,
std::span<u8> out_data) { std::span<u8> out_data) {
std::scoped_lock lock{mutex}; std::scoped_lock lock{mutex};
@ -741,8 +750,16 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 || if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
operation_result == ResultUnknown115) { operation_result == ResultUnknown115) {
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; auto static_service =
time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point; system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
static_service->GetStandardSteadyClock(steady_clock);
Service::PSC::Time::SteadyClockTimePoint time_point{};
R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
time_since_last_error = time_point.time_point;
} }
return operation_result; return operation_result;

View file

@ -13,7 +13,6 @@
#include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
namespace Service::NFC { namespace Service::NFC {
@ -42,7 +41,7 @@ public:
std::span<MifareReadBlockData> read_data); std::span<MifareReadBlockData> read_data);
Result WriteMifare(u64 device_handle, Result WriteMifare(u64 device_handle,
std::span<const MifareWriteBlockParameter> write_parameters); std::span<const MifareWriteBlockParameter> write_parameters);
Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout, Result SendCommandByPassThrough(u64 device_handle, const s64& timeout,
std::span<const u8> command_data, std::span<u8> out_data); std::span<const u8> command_data, std::span<u8> out_data);
// Nfp device manager // Nfp device manager
@ -92,7 +91,7 @@ private:
const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
bool is_initialized = false; bool is_initialized = false;
u64 time_since_last_error = 0; s64 time_since_last_error = 0;
mutable std::mutex mutex; mutable std::mutex mutex;
std::array<std::shared_ptr<NfcDevice>, 10> devices{}; std::array<std::shared_ptr<NfcDevice>, 10> devices{};

View file

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

View file

@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si
struct NTAG215File { struct NTAG215File {
u8 uid_crc_check2; u8 uid_crc_check2;
u8 internal_number; u8 internal_number;
u16 static_lock; // Set defined pages as read only u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory u32 compatibility_container; // Defines available memory
HashData hmac_data; // Hash HashData hmac_data; // Hash
u8 constant_value; // Must be A5 u8 constant_value; // Must be A5
u16_be write_counter; // Number of times the amiibo has been written? u16_be write_counter; // Number of times the amiibo has been written?
u8 amiibo_version; // Amiibo file version u8 amiibo_version; // Amiibo file version
AmiiboSettings settings; AmiiboSettings settings;
Service::Mii::Ver3StoreData owner_mii; // Mii data Service::Mii::Ver3StoreData owner_mii; // Mii data
u64_be application_id; // Game id u64_be application_id; // Game id
@ -278,7 +278,7 @@ struct EncryptedNTAG215File {
u8 uuid_crc_check2; u8 uuid_crc_check2;
u8 internal_number; u8 internal_number;
u16 static_lock; // Set defined pages as read only u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory u32 compatibility_container; // Defines available memory
EncryptedAmiiboFile user_memory; // Writable data EncryptedAmiiboFile user_memory; // Writable data
u32 dynamic_lock; // Dynamic lock u32 dynamic_lock; // Dynamic lock
u32 CFG0; // Defines memory protected by password u32 CFG0; // Defines memory protected by password

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/settings_server.h"
namespace Service::NS { namespace Service::NS {
@ -415,4 +415,4 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage
return std::nullopt; return std::nullopt;
} }
} }
} // namespace Service::NS } // namespace Service::NS

View file

@ -5,10 +5,7 @@
#include <optional> #include <optional>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/set/system_settings.h"
namespace Service::Set {
enum class LanguageCode : u64;
}
namespace Service::NS { namespace Service::NS {
/// This is nn::ns::detail::ApplicationLanguage /// This is nn::ns::detail::ApplicationLanguage

View file

@ -16,7 +16,7 @@
#include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pdm_qry.h" #include "core/hle/service/ns/pdm_qry.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/settings_server.h"
namespace Service::NS { namespace Service::NS {

View file

@ -90,7 +90,7 @@ private:
u64_le align; u64_le align;
}; };
}; };
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size");
struct IoctlFreeSpace { struct IoctlFreeSpace {
u64_le offset{}; u64_le offset{};

View file

@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices {
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_)
: nvdevice{system_}, events_interface{events_interface_} { : nvdevice{system_}, events_interface{events_interface_} {
error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier");
unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent");
} }
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
events_interface.FreeEvent(error_notifier_event); events_interface.FreeEvent(error_notifier_event);

View file

@ -51,7 +51,7 @@ enum class NvResult : u32 {
DispNoDisplaysAttached = 0x20003, DispNoDisplaysAttached = 0x20003,
DispModeNotSupported = 0x20004, DispModeNotSupported = 0x20004,
DispNotFound = 0x20005, DispNotFound = 0x20005,
DispAttachDissallowed = 0x20006, DispAttachDisallowed = 0x20006,
DispTypeNotSupported = 0x20007, DispTypeNotSupported = 0x20007,
DispAuthenticationFailed = 0x20008, DispAuthenticationFailed = 0x20008,
DispNotAttached = 0x20009, DispNotAttached = 0x20009,

View file

@ -54,8 +54,8 @@ public:
class IClkrstSession final : public ServiceFramework<IClkrstSession> { class IClkrstSession final : public ServiceFramework<IClkrstSession> {
public: public:
explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) explicit IClkrstSession(Core::System& system_, DeviceCode device_code_)
: ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) { : ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "SetClockEnabled"}, {0, nullptr, "SetClockEnabled"},
@ -93,7 +93,7 @@ private:
rb.Push<u32>(clock_rate); rb.Push<u32>(clock_rate);
} }
DeviceCode deivce_code; DeviceCode device_code;
u32 clock_rate{}; u32 clock_rate{};
}; };
@ -118,9 +118,9 @@ private:
void OpenSession(HLERequestContext& ctx) { void OpenSession(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
const auto unkonwn_input = rp.Pop<u32>(); const auto unknown_input = rp.Pop<u32>();
LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input); LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);

View file

@ -4,9 +4,13 @@
#include <memory> #include <memory>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/psc/psc.h" #include "core/hle/service/psc/psc.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/psc/time/manager.h"
#include "core/hle/service/psc/time/power_state_service.h"
#include "core/hle/service/psc/time/service_manager.h"
#include "core/hle/service/psc/time/static.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Service::PSC { namespace Service::PSC {
@ -76,6 +80,17 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
auto time = std::make_shared<Time::TimeManager>(system);
server_manager->RegisterNamedService(
"time:m", std::make_shared<Time::ServiceManager>(system, time, server_manager.get()));
server_manager->RegisterNamedService(
"time:su", std::make_shared<Time::StaticService>(
system, Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 1}, time, "time:su"));
server_manager->RegisterNamedService("time:al",
std::make_shared<Time::IAlarmService>(system, time));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

View file

@ -0,0 +1,209 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/psc/time/alarms.h"
#include "core/hle/service/psc/time/manager.h"
namespace Service::PSC::Time {
Alarm::Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type)
: m_ctx{ctx}, m_event{ctx.CreateEvent("Psc:Alarm:Event")} {
m_event->Clear();
switch (type) {
case WakeupAlarm:
m_priority = 1;
break;
case BackgroundTaskAlarm:
m_priority = 0;
break;
default:
UNREACHABLE();
return;
}
}
Alarm::~Alarm() {
m_ctx.CloseEvent(m_event);
}
Alarms::Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
PowerStateRequestManager& power_state_request_manager)
: m_system{system}, m_ctx{system, "Psc:Alarms"}, m_steady_clock{steady_clock},
m_power_state_request_manager{power_state_request_manager}, m_event{m_ctx.CreateEvent(
"Psc:Alarms:Event")} {}
Alarms::~Alarms() {
m_ctx.CloseEvent(m_event);
}
Result Alarms::Enable(Alarm& alarm, s64 time) {
R_UNLESS(m_steady_clock.IsInitialized(), ResultClockUninitialized);
std::scoped_lock l{m_mutex};
R_UNLESS(alarm.IsLinked(), ResultAlarmNotRegistered);
auto time_ns{time + m_steady_clock.GetRawTime()};
auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
time_ns = Common::AlignUp(time_ns, one_second_ns);
alarm.SetAlertTime(time_ns);
Insert(alarm);
R_RETURN(UpdateClosestAndSignal());
}
void Alarms::Disable(Alarm& alarm) {
std::scoped_lock l{m_mutex};
if (!alarm.IsLinked()) {
return;
}
Erase(alarm);
UpdateClosestAndSignal();
}
void Alarms::CheckAndSignal() {
std::scoped_lock l{m_mutex};
if (m_alarms.empty()) {
return;
}
bool alarm_signalled{false};
for (auto& alarm : m_alarms) {
if (m_steady_clock.GetRawTime() >= alarm.GetAlertTime()) {
alarm.Signal();
alarm.Lock();
Erase(alarm);
m_power_state_request_manager.UpdatePendingPowerStateRequestPriority(
alarm.GetPriority());
alarm_signalled = true;
}
}
if (!alarm_signalled) {
return;
}
m_power_state_request_manager.SignalPowerStateRequestAvailability();
UpdateClosestAndSignal();
}
bool Alarms::GetClosestAlarm(Alarm** out_alarm) {
std::scoped_lock l{m_mutex};
auto alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
*out_alarm = alarm;
return alarm != nullptr;
}
void Alarms::Insert(Alarm& alarm) {
// Alarms are sorted by alert time, then priority
auto it{m_alarms.begin()};
while (it != m_alarms.end()) {
if (alarm.GetAlertTime() < it->GetAlertTime() ||
(alarm.GetAlertTime() == it->GetAlertTime() &&
alarm.GetPriority() < it->GetPriority())) {
m_alarms.insert(it, alarm);
return;
}
it++;
}
m_alarms.push_back(alarm);
}
void Alarms::Erase(Alarm& alarm) {
m_alarms.erase(m_alarms.iterator_to(alarm));
}
Result Alarms::UpdateClosestAndSignal() {
m_closest_alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
R_SUCCEED_IF(m_closest_alarm == nullptr);
m_event->Signal();
R_SUCCEED();
}
IAlarmService::IAlarmService(Core::System& system_, std::shared_ptr<TimeManager> manager)
: ServiceFramework{system_, "time:al"}, m_system{system}, m_alarms{manager->m_alarms} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAlarmService::CreateWakeupAlarm, "CreateWakeupAlarm"},
{1, &IAlarmService::CreateBackgroundTaskAlarm, "CreateBackgroundTaskAlarm"},
};
// clang-format on
RegisterHandlers(functions);
}
void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm);
}
void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm);
}
ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type)
: ServiceFramework{system_, "ISteadyClockAlarm"}, m_ctx{system, "Psc:ISteadyClockAlarm"},
m_alarms{alarms}, m_alarm{system, m_ctx, type} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISteadyClockAlarm::GetAlarmEvent, "GetAlarmEvent"},
{1, &ISteadyClockAlarm::Enable, "Enable"},
{2, &ISteadyClockAlarm::Disable, "Disable"},
{3, &ISteadyClockAlarm::IsEnabled, "IsEnabled"},
{10, nullptr, "CreateWakeLock"},
{11, nullptr, "DestroyWakeLock"},
};
// clang-format on
RegisterHandlers(functions);
}
void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(m_alarm.GetEventHandle());
}
void ISteadyClockAlarm::Enable(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::RequestParser rp{ctx};
auto time{rp.Pop<s64>()};
auto res = m_alarms.Enable(m_alarm, time);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
}
void ISteadyClockAlarm::Disable(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
m_alarms.Disable(m_alarm);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISteadyClockAlarm::IsEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called.");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<bool>(m_alarm.IsLinked());
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,139 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
#include "core/hle/service/psc/time/common.h"
#include "core/hle/service/psc/time/power_state_request_manager.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class TimeManager;
enum AlarmType : u32 {
WakeupAlarm = 0,
BackgroundTaskAlarm = 1,
};
struct Alarm : public Common::IntrusiveListBaseNode<Alarm> {
using AlarmList = Common::IntrusiveListBaseTraits<Alarm>::ListType;
Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type);
~Alarm();
Kernel::KReadableEvent& GetEventHandle() {
return m_event->GetReadableEvent();
}
s64 GetAlertTime() const {
return m_alert_time;
}
void SetAlertTime(s64 time) {
m_alert_time = time;
}
u32 GetPriority() const {
return m_priority;
}
void Signal() {
m_event->Signal();
}
Result Lock() {
// TODO
// if (m_lock_service) {
// return m_lock_service->Lock();
// }
R_SUCCEED();
}
KernelHelpers::ServiceContext& m_ctx;
u32 m_priority;
Kernel::KEvent* m_event{};
s64 m_alert_time{};
// TODO
// nn::psc::sf::IPmStateLock* m_lock_service{};
};
class Alarms {
public:
explicit Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
PowerStateRequestManager& power_state_request_manager);
~Alarms();
Kernel::KEvent& GetEvent() {
return *m_event;
}
s64 GetRawTime() {
return m_steady_clock.GetRawTime();
}
Result Enable(Alarm& alarm, s64 time);
void Disable(Alarm& alarm);
void CheckAndSignal();
bool GetClosestAlarm(Alarm** out_alarm);
private:
void Insert(Alarm& alarm);
void Erase(Alarm& alarm);
Result UpdateClosestAndSignal();
Core::System& m_system;
KernelHelpers::ServiceContext m_ctx;
StandardSteadyClockCore& m_steady_clock;
PowerStateRequestManager& m_power_state_request_manager;
Alarm::AlarmList m_alarms;
Kernel::KEvent* m_event{};
Alarm* m_closest_alarm{};
std::mutex m_mutex;
};
class IAlarmService final : public ServiceFramework<IAlarmService> {
public:
explicit IAlarmService(Core::System& system, std::shared_ptr<TimeManager> manager);
~IAlarmService() override = default;
private:
void CreateWakeupAlarm(HLERequestContext& ctx);
void CreateBackgroundTaskAlarm(HLERequestContext& ctx);
Core::System& m_system;
Alarms& m_alarms;
};
class ISteadyClockAlarm final : public ServiceFramework<ISteadyClockAlarm> {
public:
explicit ISteadyClockAlarm(Core::System& system, Alarms& alarms, AlarmType type);
~ISteadyClockAlarm() override = default;
private:
void GetAlarmEvent(HLERequestContext& ctx);
void Enable(HLERequestContext& ctx);
void Disable(HLERequestContext& ctx);
void IsEnabled(HLERequestContext& ctx);
KernelHelpers::ServiceContext m_ctx;
Alarms& m_alarms;
Alarm m_alarm;
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/psc/time/clocks/context_writers.h"
namespace Service::PSC::Time {
void ContextWriter::SignalAllNodes() {
std::scoped_lock l{m_mutex};
for (auto& operation : m_operation_events) {
operation.m_event->Signal();
}
}
void ContextWriter::Link(OperationEvent& operation_event) {
std::scoped_lock l{m_mutex};
m_operation_events.push_back(operation_event);
}
LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& system,
SharedMemory& shared_memory)
: m_system{system}, m_shared_memory{shared_memory} {}
Result LocalSystemClockContextWriter::Write(SystemClockContext& context) {
if (m_in_use) {
R_SUCCEED_IF(context == m_context);
m_context = context;
} else {
m_context = context;
m_in_use = true;
}
m_shared_memory.SetLocalSystemContext(context);
SignalAllNodes();
R_SUCCEED();
}
NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& system,
SharedMemory& shared_memory,
SystemClockCore& system_clock)
: m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {}
Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) {
s64 time{};
[[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time);
if (m_in_use) {
R_SUCCEED_IF(context == m_context);
m_context = context;
} else {
m_context = context;
m_in_use = true;
}
m_shared_memory.SetNetworkSystemContext(context);
SignalAllNodes();
R_SUCCEED();
}
EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWriter(
Core::System& system)
: m_system{system} {}
Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) {
if (m_in_use) {
R_SUCCEED_IF(context == m_context);
m_context = context;
} else {
m_context = context;
m_in_use = true;
}
SignalAllNodes();
R_SUCCEED();
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <list>
#include "common/common_types.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
#include "core/hle/service/psc/time/common.h"
#include "core/hle/service/psc/time/shared_memory.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class ContextWriter {
private:
using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType;
public:
virtual ~ContextWriter() = default;
virtual Result Write(SystemClockContext& context) = 0;
void SignalAllNodes();
void Link(OperationEvent& operation_event);
private:
OperationEventList m_operation_events;
std::mutex m_mutex;
};
class LocalSystemClockContextWriter : public ContextWriter {
public:
explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory);
Result Write(SystemClockContext& context) override;
private:
Core::System& m_system;
SharedMemory& m_shared_memory;
bool m_in_use{};
SystemClockContext m_context{};
};
class NetworkSystemClockContextWriter : public ContextWriter {
public:
explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory,
SystemClockCore& system_clock);
Result Write(SystemClockContext& context) override;
private:
Core::System& m_system;
SharedMemory& m_shared_memory;
bool m_in_use{};
SystemClockContext m_context{};
SystemClockCore& m_system_clock;
};
class EphemeralNetworkSystemClockContextWriter : public ContextWriter {
public:
EphemeralNetworkSystemClockContextWriter(Core::System& system);
Result Write(SystemClockContext& context) override;
private:
Core::System& m_system;
bool m_in_use{};
SystemClockContext m_context{};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/psc/time/clocks/context_writers.h"
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
#include "core/hle/service/psc/time/common.h"
namespace Service::PSC::Time {
class EphemeralNetworkSystemClockCore : public SystemClockCore {
public:
explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock)
: SystemClockCore{steady_clock} {}
~EphemeralNetworkSystemClockCore() override = default;
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
namespace Service::PSC::Time {
void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) {
SteadyClockTimePoint time_point{};
if (GetCurrentTimePoint(time_point) == ResultSuccess &&
context.steady_time_point.IdMatches(time_point)) {
SetContextAndWrite(context);
} else if (SetCurrentTime(time) != ResultSuccess) {
LOG_ERROR(Service_Time, "Failed to SetCurrentTime");
}
SetInitialized();
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/psc/time/clocks/context_writers.h"
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
#include "core/hle/service/psc/time/common.h"
namespace Service::PSC::Time {
class StandardLocalSystemClockCore : public SystemClockCore {
public:
explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock)
: SystemClockCore{steady_clock} {}
~StandardLocalSystemClockCore() override = default;
void Initialize(SystemClockContext& context, s64 time);
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
namespace Service::PSC::Time {
void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) {
if (SetContextAndWrite(context) != ResultSuccess) {
LOG_ERROR(Service_Time, "Failed to SetContext");
}
m_sufficient_accuracy = accuracy;
SetInitialized();
}
bool StandardNetworkSystemClockCore::IsAccuracySufficient() {
if (!IsInitialized()) {
return false;
}
SystemClockContext context{};
SteadyClockTimePoint current_time_point{};
if (GetCurrentTimePoint(current_time_point) != ResultSuccess ||
GetContext(context) != ResultSuccess) {
return false;
}
s64 seconds{};
if (GetSpanBetweenTimePoints(&seconds, context.steady_time_point, current_time_point) !=
ResultSuccess) {
return false;
}
if (std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(seconds))
.count() < m_sufficient_accuracy) {
return true;
}
return false;
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <chrono>
#include "core/hle/result.h"
#include "core/hle/service/psc/time/clocks/context_writers.h"
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
#include "core/hle/service/psc/time/common.h"
namespace Service::PSC::Time {
class StandardNetworkSystemClockCore : public SystemClockCore {
public:
explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock)
: SystemClockCore{steady_clock} {}
~StandardNetworkSystemClockCore() override = default;
void Initialize(SystemClockContext& context, s64 accuracy);
bool IsAccuracySufficient();
private:
s64 m_sufficient_accuracy{
std::chrono ::duration_cast<std::chrono::nanoseconds>(std::chrono::days(10)).count()};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,100 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
namespace Service::PSC::Time {
void StandardSteadyClockCore::Initialize(ClockSourceId clock_source_id, s64 rtc_offset,
s64 internal_offset, s64 test_offset,
bool is_rtc_reset_detected) {
m_clock_source_id = clock_source_id;
m_rtc_offset = rtc_offset;
m_internal_offset = internal_offset;
m_test_offset = test_offset;
if (is_rtc_reset_detected) {
SetResetDetected();
}
SetInitialized();
}
void StandardSteadyClockCore::SetRtcOffset(s64 offset) {
m_rtc_offset = offset;
}
void StandardSteadyClockCore::SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time) {
auto ticks{m_system.CoreTiming().GetClockTicks()};
m_continuous_adjustment_time_point.rtc_offset = ConvertToTimeSpan(ticks).count();
m_continuous_adjustment_time_point.diff_scale = 0;
m_continuous_adjustment_time_point.shift_amount = 0;
m_continuous_adjustment_time_point.lower = time;
m_continuous_adjustment_time_point.upper = time;
m_continuous_adjustment_time_point.clock_source_id = clock_source_id;
}
void StandardSteadyClockCore::GetContinuousAdjustment(
ContinuousAdjustmentTimePoint& out_time_point) const {
out_time_point = m_continuous_adjustment_time_point;
}
void StandardSteadyClockCore::UpdateContinuousAdjustmentTime(s64 in_time) {
auto ticks{m_system.CoreTiming().GetClockTicks()};
auto global_time_ns{ConvertToTimeSpan(ticks).count()};
auto expected_time{((global_time_ns - m_continuous_adjustment_time_point.rtc_offset) *
m_continuous_adjustment_time_point.diff_scale) >>
m_continuous_adjustment_time_point.shift_amount};
auto last_time_point{m_continuous_adjustment_time_point.upper};
m_continuous_adjustment_time_point.upper = in_time;
auto t1{std::min<s64>(expected_time, last_time_point)};
expected_time = std::max<s64>(expected_time, last_time_point);
expected_time = m_continuous_adjustment_time_point.diff_scale >= 0 ? t1 : expected_time;
auto new_diff{in_time < expected_time ? -55 : 55};
m_continuous_adjustment_time_point.rtc_offset = global_time_ns;
m_continuous_adjustment_time_point.shift_amount = expected_time == in_time ? 0 : 14;
m_continuous_adjustment_time_point.diff_scale = expected_time == in_time ? 0 : new_diff;
m_continuous_adjustment_time_point.lower = expected_time;
}
Result StandardSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) {
auto current_time_ns = GetCurrentRawTimePointImpl();
auto current_time_s =
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds(current_time_ns));
out_time_point.time_point = current_time_s.count();
out_time_point.clock_source_id = m_clock_source_id;
R_SUCCEED();
}
s64 StandardSteadyClockCore::GetCurrentRawTimePointImpl() {
std::scoped_lock l{m_mutex};
auto ticks{static_cast<s64>(m_system.CoreTiming().GetClockTicks())};
auto current_time_ns = m_rtc_offset + ConvertToTimeSpan(ticks).count();
auto time_point = std::max<s64>(current_time_ns, m_cached_time_point);
m_cached_time_point = time_point;
return time_point;
}
s64 StandardSteadyClockCore::GetTestOffsetImpl() const {
return m_test_offset;
}
void StandardSteadyClockCore::SetTestOffsetImpl(s64 offset) {
m_test_offset = offset;
}
s64 StandardSteadyClockCore::GetInternalOffsetImpl() const {
return m_internal_offset;
}
void StandardSteadyClockCore::SetInternalOffsetImpl(s64 offset) {
m_internal_offset = offset;
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class StandardSteadyClockCore : public SteadyClockCore {
public:
explicit StandardSteadyClockCore(Core::System& system) : m_system{system} {}
~StandardSteadyClockCore() override = default;
void Initialize(ClockSourceId clock_source_id, s64 rtc_offset, s64 internal_offset,
s64 test_offset, bool is_rtc_reset_detected);
void SetRtcOffset(s64 offset);
void SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time);
void GetContinuousAdjustment(ContinuousAdjustmentTimePoint& out_time_point) const;
void UpdateContinuousAdjustmentTime(s64 time);
Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override;
s64 GetCurrentRawTimePointImpl() override;
s64 GetTestOffsetImpl() const override;
void SetTestOffsetImpl(s64 offset) override;
s64 GetInternalOffsetImpl() const override;
void SetInternalOffsetImpl(s64 offset) override;
Result GetRtcValueImpl(s64& out_value) override {
R_RETURN(ResultNotImplemented);
}
Result GetSetupResultValueImpl() override {
R_SUCCEED();
}
private:
Core::System& m_system;
std::mutex m_mutex;
s64 m_test_offset{};
s64 m_internal_offset{};
ClockSourceId m_clock_source_id{};
s64 m_rtc_offset{};
s64 m_cached_time_point{};
ContinuousAdjustmentTimePoint m_continuous_adjustment_time_point{};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
namespace Service::PSC::Time {
StandardUserSystemClockCore::StandardUserSystemClockCore(
Core::System& system, StandardLocalSystemClockCore& local_clock,
StandardNetworkSystemClockCore& network_clock)
: SystemClockCore{local_clock.GetSteadyClock()}, m_system{system},
m_ctx{m_system, "Psc:StandardUserSystemClockCore"}, m_local_system_clock{local_clock},
m_network_system_clock{network_clock}, m_event{m_ctx.CreateEvent(
"Psc:StandardUserSystemClockCore:Event")} {}
StandardUserSystemClockCore::~StandardUserSystemClockCore() {
m_ctx.CloseEvent(m_event);
}
Result StandardUserSystemClockCore::SetAutomaticCorrection(bool automatic_correction) {
if (m_automatic_correction == automatic_correction ||
!m_network_system_clock.CheckClockSourceMatches()) {
m_automatic_correction = automatic_correction;
R_SUCCEED();
}
SystemClockContext context{};
R_TRY(m_network_system_clock.GetContext(context));
R_TRY(m_local_system_clock.SetContextAndWrite(context));
m_automatic_correction = automatic_correction;
R_SUCCEED();
}
Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context) const {
if (!m_automatic_correction) {
R_RETURN(m_local_system_clock.GetContext(out_context));
}
if (!m_network_system_clock.CheckClockSourceMatches()) {
R_RETURN(m_local_system_clock.GetContext(out_context));
}
SystemClockContext context{};
R_TRY(m_network_system_clock.GetContext(context));
R_TRY(m_local_system_clock.SetContextAndWrite(context));
R_RETURN(m_local_system_clock.GetContext(out_context));
}
Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) {
R_RETURN(ResultNotImplemented);
}
Result StandardUserSystemClockCore::GetTimePoint(SteadyClockTimePoint& out_time_point) {
out_time_point = m_time_point;
R_SUCCEED();
}
void StandardUserSystemClockCore::SetTimePointAndSignal(SteadyClockTimePoint& time_point) {
m_time_point = time_point;
m_event->Signal();
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/kernel/k_event.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/psc/time/clocks/context_writers.h"
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
#include "core/hle/service/psc/time/common.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class StandardUserSystemClockCore : public SystemClockCore {
public:
explicit StandardUserSystemClockCore(Core::System& system,
StandardLocalSystemClockCore& local_clock,
StandardNetworkSystemClockCore& network_clock);
~StandardUserSystemClockCore() override;
Kernel::KEvent& GetEvent() {
return *m_event;
}
bool GetAutomaticCorrection() const {
return m_automatic_correction;
}
Result SetAutomaticCorrection(bool automatic_correction);
Result GetContext(SystemClockContext& out_context) const override;
Result SetContext(SystemClockContext& context) override;
Result GetTimePoint(SteadyClockTimePoint& out_time_point);
void SetTimePointAndSignal(SteadyClockTimePoint& time_point);
private:
Core::System& m_system;
KernelHelpers::ServiceContext m_ctx;
bool m_automatic_correction{};
StandardLocalSystemClockCore& m_local_system_clock;
StandardNetworkSystemClockCore& m_network_system_clock;
SteadyClockTimePoint m_time_point{};
Kernel::KEvent* m_event{};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <chrono>
#include "core/hle/result.h"
#include "core/hle/service/psc/time/common.h"
namespace Service::PSC::Time {
class SteadyClockCore {
public:
SteadyClockCore() = default;
virtual ~SteadyClockCore() = default;
void SetInitialized() {
m_initialized = true;
}
bool IsInitialized() const {
return m_initialized;
}
void SetResetDetected() {
m_reset_detected = true;
}
bool IsResetDetected() const {
return m_reset_detected;
}
Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
R_TRY(GetCurrentTimePointImpl(out_time_point));
auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
out_time_point.time_point += GetTestOffsetImpl() / one_second_ns;
out_time_point.time_point += GetInternalOffsetImpl() / one_second_ns;
R_SUCCEED();
}
s64 GetTestOffset() const {
return GetTestOffsetImpl();
}
void SetTestOffset(s64 offset) {
SetTestOffsetImpl(offset);
}
s64 GetInternalOffset() const {
return GetInternalOffsetImpl();
}
s64 GetRawTime() {
return GetCurrentRawTimePointImpl() + GetTestOffsetImpl() + GetInternalOffsetImpl();
}
Result GetRtcValue(s64& out_value) {
R_RETURN(GetRtcValueImpl(out_value));
}
Result GetSetupResultValue() {
R_RETURN(GetSetupResultValueImpl());
}
private:
virtual Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) = 0;
virtual s64 GetCurrentRawTimePointImpl() = 0;
virtual s64 GetTestOffsetImpl() const = 0;
virtual void SetTestOffsetImpl(s64 offset) = 0;
virtual s64 GetInternalOffsetImpl() const = 0;
virtual void SetInternalOffsetImpl(s64 offset) = 0;
virtual Result GetRtcValueImpl(s64& out_value) = 0;
virtual Result GetSetupResultValueImpl() = 0;
bool m_initialized{};
bool m_reset_detected{};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/psc/time/clocks/context_writers.h"
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
namespace Service::PSC::Time {
bool SystemClockCore::CheckClockSourceMatches() {
SystemClockContext context{};
if (GetContext(context) != ResultSuccess) {
return false;
}
SteadyClockTimePoint time_point{};
if (m_steady_clock.GetCurrentTimePoint(time_point) != ResultSuccess) {
return false;
}
return context.steady_time_point.IdMatches(time_point);
}
Result SystemClockCore::GetCurrentTime(s64* out_time) const {
R_UNLESS(out_time != nullptr, ResultInvalidArgument);
SystemClockContext context{};
SteadyClockTimePoint time_point{};
R_TRY(m_steady_clock.GetCurrentTimePoint(time_point));
R_TRY(GetContext(context));
R_UNLESS(context.steady_time_point.IdMatches(time_point), ResultClockMismatch);
*out_time = context.offset + time_point.time_point;
R_SUCCEED();
}
Result SystemClockCore::SetCurrentTime(s64 time) {
SteadyClockTimePoint time_point{};
R_TRY(m_steady_clock.GetCurrentTimePoint(time_point));
SystemClockContext context{
.offset = time - time_point.time_point,
.steady_time_point = time_point,
};
R_RETURN(SetContextAndWrite(context));
}
Result SystemClockCore::GetContext(SystemClockContext& out_context) const {
out_context = m_context;
R_SUCCEED();
}
Result SystemClockCore::SetContext(SystemClockContext& context) {
m_context = context;
R_SUCCEED();
}
Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) {
R_TRY(SetContext(context));
if (m_context_writer) {
R_RETURN(m_context_writer->Write(context));
}
R_SUCCEED();
}
void SystemClockCore::LinkOperationEvent(OperationEvent& operation_event) {
if (m_context_writer) {
m_context_writer->Link(operation_event);
}
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
#include "core/hle/service/psc/time/common.h"
namespace Service::PSC::Time {
class ContextWriter;
class SystemClockCore {
public:
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
virtual ~SystemClockCore() = default;
SteadyClockCore& GetSteadyClock() {
return m_steady_clock;
}
bool IsInitialized() const {
return m_initialized;
}
void SetInitialized() {
m_initialized = true;
}
void SetContextWriter(ContextWriter& context_writer) {
m_context_writer = &context_writer;
}
bool CheckClockSourceMatches();
Result GetCurrentTime(s64* out_time) const;
Result SetCurrentTime(s64 time);
Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
R_RETURN(m_steady_clock.GetCurrentTimePoint(out_time_point));
}
virtual Result GetContext(SystemClockContext& out_context) const;
virtual Result SetContext(SystemClockContext& context);
Result SetContextAndWrite(SystemClockContext& context);
void LinkOperationEvent(OperationEvent& operation_event);
private:
bool m_initialized{};
ContextWriter* m_context_writer{};
SteadyClockCore& m_steady_clock;
SystemClockContext m_context{};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h"
namespace Service::PSC::Time {
Result TickBasedSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) {
auto ticks{m_system.CoreTiming().GetClockTicks()};
auto current_time_s =
std::chrono::duration_cast<std::chrono::seconds>(ConvertToTimeSpan(ticks)).count();
out_time_point.time_point = current_time_s;
out_time_point.clock_source_id = m_clock_source_id;
R_SUCCEED();
}
s64 TickBasedSteadyClockCore::GetCurrentRawTimePointImpl() {
SteadyClockTimePoint time_point{};
if (GetCurrentTimePointImpl(time_point) != ResultSuccess) {
LOG_ERROR(Service_Time, "Failed to GetCurrentTimePoint!");
}
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::seconds(time_point.time_point))
.count();
}
s64 TickBasedSteadyClockCore::GetTestOffsetImpl() const {
return 0;
}
void TickBasedSteadyClockCore::SetTestOffsetImpl(s64 offset) {}
s64 TickBasedSteadyClockCore::GetInternalOffsetImpl() const {
return 0;
}
void TickBasedSteadyClockCore::SetInternalOffsetImpl(s64 offset) {}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include "common/uuid.h"
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class TickBasedSteadyClockCore : public SteadyClockCore {
public:
explicit TickBasedSteadyClockCore(Core::System& system) : m_system{system} {}
~TickBasedSteadyClockCore() override = default;
Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override;
s64 GetCurrentRawTimePointImpl() override;
s64 GetTestOffsetImpl() const override;
void SetTestOffsetImpl(s64 offset) override;
s64 GetInternalOffsetImpl() const override;
void SetInternalOffsetImpl(s64 offset) override;
Result GetRtcValueImpl(s64& out_value) override {
R_RETURN(ResultNotImplemented);
}
Result GetSetupResultValueImpl() override {
R_SUCCEED();
}
private:
Core::System& m_system;
ClockSourceId m_clock_source_id{Common::UUID::MakeRandom()};
};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/psc/time/common.h"
namespace Service::PSC::Time {
OperationEvent::OperationEvent(Core::System& system)
: m_ctx{system, "Time:OperationEvent"}, m_event{
m_ctx.CreateEvent("Time:OperationEvent:Event")} {}
OperationEvent::~OperationEvent() {
m_ctx.CloseEvent(m_event);
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,168 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <chrono>
#include "common/common_types.h"
#include "common/intrusive_list.h"
#include "common/uuid.h"
#include "common/wall_clock.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/psc/time/errors.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
using ClockSourceId = Common::UUID;
struct SteadyClockTimePoint {
constexpr bool IdMatches(SteadyClockTimePoint& other) {
return clock_source_id == other.clock_source_id;
}
bool operator==(const SteadyClockTimePoint& other) const = default;
s64 time_point;
ClockSourceId clock_source_id;
};
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint has the wrong size!");
static_assert(std::is_trivial_v<ClockSourceId>);
struct SystemClockContext {
bool operator==(const SystemClockContext& other) const = default;
s64 offset;
SteadyClockTimePoint steady_time_point;
};
static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!");
static_assert(std::is_trivial_v<SystemClockContext>);
enum class TimeType : u8 {
UserSystemClock,
NetworkSystemClock,
LocalSystemClock,
};
struct CalendarTime {
s16 year;
s8 month;
s8 day;
s8 hour;
s8 minute;
s8 second;
};
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime has the wrong size!");
struct CalendarAdditionalInfo {
s32 day_of_week;
s32 day_of_year;
std::array<char, 8> name;
s32 is_dst;
s32 ut_offset;
};
static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!");
struct LocationName {
std::array<char, 36> name;
};
static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!");
struct RuleVersion {
std::array<char, 16> version;
};
static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!");
struct ClockSnapshot {
SystemClockContext user_context;
SystemClockContext network_context;
s64 user_time;
s64 network_time;
CalendarTime user_calendar_time;
CalendarTime network_calendar_time;
CalendarAdditionalInfo user_calendar_additional_time;
CalendarAdditionalInfo network_calendar_additional_time;
SteadyClockTimePoint steady_clock_time_point;
LocationName location_name;
bool is_automatic_correction_enabled;
TimeType type;
u16 unk_CE;
};
static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot has the wrong size!");
static_assert(std::is_trivial_v<ClockSnapshot>);
struct ContinuousAdjustmentTimePoint {
s64 rtc_offset;
s64 diff_scale;
s64 shift_amount;
s64 lower;
s64 upper;
ClockSourceId clock_source_id;
};
static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38,
"ContinuousAdjustmentTimePoint has the wrong size!");
static_assert(std::is_trivial_v<ContinuousAdjustmentTimePoint>);
struct AlarmInfo {
s64 alert_time;
u32 priority;
};
static_assert(sizeof(AlarmInfo) == 0x10, "AlarmInfo has the wrong size!");
struct StaticServiceSetupInfo {
bool can_write_local_clock;
bool can_write_user_clock;
bool can_write_network_clock;
bool can_write_timezone_device_location;
bool can_write_steady_clock;
bool can_write_uninitialized_clock;
};
static_assert(sizeof(StaticServiceSetupInfo) == 0x6, "StaticServiceSetupInfo has the wrong size!");
struct OperationEvent : public Common::IntrusiveListBaseNode<OperationEvent> {
using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType;
OperationEvent(Core::System& system);
~OperationEvent();
KernelHelpers::ServiceContext m_ctx;
Kernel::KEvent* m_event{};
};
constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) {
constexpr auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
constexpr s64 max{Common::WallClock::CNTFRQ *
(std::numeric_limits<s64>::max() / one_second_ns)};
if (ticks > max) {
return std::chrono::nanoseconds(std::numeric_limits<s64>::max());
} else if (ticks < -max) {
return std::chrono::nanoseconds(std::numeric_limits<s64>::min());
}
auto a{ticks / Common::WallClock::CNTFRQ * one_second_ns};
auto b{((ticks % Common::WallClock::CNTFRQ) * one_second_ns) / Common::WallClock::CNTFRQ};
return std::chrono::nanoseconds(a + b);
}
constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTimePoint& a,
SteadyClockTimePoint& b) {
R_UNLESS(out_seconds, ResultInvalidArgument);
R_UNLESS(a.IdMatches(b), ResultInvalidArgument);
R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(),
ResultOverflow);
R_UNLESS(a.time_point < 0 || b.time_point >= a.time_point + std::numeric_limits<s64>::min(),
ResultOverflow);
*out_seconds = b.time_point - a.time_point;
R_SUCCEED();
}
} // namespace Service::PSC::Time

View file

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::PSC::Time {
constexpr Result ResultPermissionDenied{ErrorModule::Time, 1};
constexpr Result ResultClockMismatch{ErrorModule::Time, 102};
constexpr Result ResultClockUninitialized{ErrorModule::Time, 103};
constexpr Result ResultTimeNotFound{ErrorModule::Time, 200};
constexpr Result ResultOverflow{ErrorModule::Time, 201};
constexpr Result ResultFailed{ErrorModule::Time, 801};
constexpr Result ResultInvalidArgument{ErrorModule::Time, 901};
constexpr Result ResultTimeZoneOutOfRange{ErrorModule::Time, 902};
constexpr Result ResultTimeZoneParseFailed{ErrorModule::Time, 903};
constexpr Result ResultRtcTimeout{ErrorModule::Time, 988};
constexpr Result ResultTimeZoneNotFound{ErrorModule::Time, 989};
constexpr Result ResultNotImplemented{ErrorModule::Time, 990};
constexpr Result ResultAlarmNotRegistered{ErrorModule::Time, 1502};
} // namespace Service::PSC::Time

View file

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/psc/time/alarms.h"
#include "core/hle/service/psc/time/clocks/context_writers.h"
#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h"
#include "core/hle/service/psc/time/power_state_request_manager.h"
#include "core/hle/service/psc/time/shared_memory.h"
#include "core/hle/service/psc/time/time_zone.h"
namespace Core {
class System;
}
namespace Service::PSC::Time {
class TimeManager {
public:
explicit TimeManager(Core::System& system)
: m_system{system}, m_standard_steady_clock{system}, m_tick_based_steady_clock{m_system},
m_standard_local_system_clock{m_standard_steady_clock},
m_standard_network_system_clock{m_standard_steady_clock},
m_standard_user_system_clock{m_system, m_standard_local_system_clock,
m_standard_network_system_clock},
m_ephemeral_network_clock{m_tick_based_steady_clock}, m_shared_memory{m_system},
m_power_state_request_manager{m_system}, m_alarms{m_system, m_standard_steady_clock,
m_power_state_request_manager},
m_local_system_clock_context_writer{m_system, m_shared_memory},
m_network_system_clock_context_writer{m_system, m_shared_memory,
m_standard_user_system_clock},
m_ephemeral_network_clock_context_writer{m_system} {}
Core::System& m_system;
StandardSteadyClockCore m_standard_steady_clock;
TickBasedSteadyClockCore m_tick_based_steady_clock;
StandardLocalSystemClockCore m_standard_local_system_clock;
StandardNetworkSystemClockCore m_standard_network_system_clock;
StandardUserSystemClockCore m_standard_user_system_clock;
EphemeralNetworkSystemClockCore m_ephemeral_network_clock;
TimeZone m_time_zone;
SharedMemory m_shared_memory;
PowerStateRequestManager m_power_state_request_manager;
Alarms m_alarms;
LocalSystemClockContextWriter m_local_system_clock_context_writer;
NetworkSystemClockContextWriter m_network_system_clock_context_writer;
EphemeralNetworkSystemClockContextWriter m_ephemeral_network_clock_context_writer;
};
} // namespace Service::PSC::Time

Some files were not shown because too many files have changed in this diff Show more