Merge yuzu-emu#13174

This commit is contained in:
yuzubot 2024-03-04 00:57:21 +00:00
parent adc597a799
commit 70711ddb39
15 changed files with 181 additions and 185 deletions

View file

@ -343,7 +343,7 @@ void SetColorConsoleBackendEnabled(bool enabled) {
} }
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format, unsigned int line_num, const char* function, fmt::string_view format,
const fmt::format_args& args) { const fmt::format_args& args) {
if (!initialization_in_progress_suppress_logging) { if (!initialization_in_progress_suppress_logging) {
Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function,

View file

@ -24,12 +24,12 @@ constexpr const char* TrimSourcePath(std::string_view source) {
/// Logs a message to the global logger, using fmt /// Logs a message to the global logger, using fmt
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format, unsigned int line_num, const char* function, fmt::string_view format,
const fmt::format_args& args); const fmt::format_args& args);
template <typename... Args> template <typename... Args>
void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num, void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, const char* format, const Args&... args) { const char* function, fmt::format_string<Args...> format, const Args&... args) {
FmtLogMessageImpl(log_class, log_level, filename, line_num, function, format, FmtLogMessageImpl(log_class, log_level, filename, line_num, function, format,
fmt::make_format_args(args...)); fmt::make_format_args(args...));
} }

View file

@ -105,12 +105,4 @@ VirtualDir PartitionFilesystem::GetParentDirectory() const {
return nullptr; return nullptr;
} }
void PartitionFilesystem::PrintDebugInfo() const {
LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic);
LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
for (u32 i = 0; i < pfs_header.num_entries; i++) {
LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes)", i,
pfs_files[i]->GetName(), pfs_files[i]->GetSize());
}
}
} // namespace FileSys } // namespace FileSys

View file

@ -35,7 +35,6 @@ public:
std::vector<VirtualDir> GetSubdirectories() const override; std::vector<VirtualDir> GetSubdirectories() const override;
std::string GetName() const override; std::string GetName() const override;
VirtualDir GetParentDirectory() const override; VirtualDir GetParentDirectory() const override;
void PrintDebugInfo() const;
private: private:
struct Header { struct Header {

View file

@ -11,7 +11,6 @@
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
#include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc.h"
#include "core/hle/service/glue/time/manager.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/service_manager.h"
#include "core/hle/service/psc/time/static.h" #include "core/hle/service/psc/time/static.h"
#include "core/hle/service/psc/time/system_clock.h" #include "core/hle/service/psc/time/system_clock.h"
@ -20,8 +19,8 @@
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time { namespace Service::Glue::Time {
namespace {
s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) { static s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
constexpr auto is_leap = [](s32 year) -> bool { constexpr auto is_leap = [](s32 year) -> bool {
return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)); return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
}; };
@ -50,7 +49,8 @@ s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
return epoch_s - 62135683200ll; return epoch_s - 62135683200ll;
} }
s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) { static s64 GetEpochTimeFromInitialYear(
std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) {
s32 year{2000}; s32 year{2000};
set_sys->GetSettingsItemValueImpl(year, "time", "standard_user_clock_initial_year"); set_sys->GetSettingsItemValueImpl(year, "time", "standard_user_clock_initial_year");
@ -65,31 +65,32 @@ s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsSer
return CalendarTimeToEpoch(calendar); return CalendarTimeToEpoch(calendar);
} }
Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationName& in_name) { static Service::PSC::Time::LocationName GetTimeZoneString(
TimeZoneBinary& time_zone_binary, Service::PSC::Time::LocationName& in_name) {
auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
Service::PSC::Time::LocationName configured_name{}; Service::PSC::Time::LocationName configured_name{};
std::memcpy(configured_name.data(), configured_zone.data(), std::memcpy(configured_name.data(), configured_zone.data(),
std::min(configured_name.size(), configured_zone.size())); std::min(configured_name.size(), configured_zone.size()));
if (!IsTimeZoneBinaryValid(configured_name)) { if (!time_zone_binary.IsValid(configured_name)) {
configured_zone = Common::TimeZone::FindSystemTimeZone(); configured_zone = Common::TimeZone::FindSystemTimeZone();
configured_name = {}; configured_name = {};
std::memcpy(configured_name.data(), configured_zone.data(), std::memcpy(configured_name.data(), configured_zone.data(),
std::min(configured_name.size(), configured_zone.size())); std::min(configured_name.size(), configured_zone.size()));
} }
ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!", ASSERT_MSG(time_zone_binary.IsValid(configured_name), "Invalid time zone {}!",
configured_name.data()); configured_name.data());
return configured_name; return configured_name;
} }
} // namespace
TimeManager::TimeManager(Core::System& system) TimeManager::TimeManager(Core::System& system)
: m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource, : m_steady_clock_resource{system}, m_time_zone_binary{system}, m_worker{
m_file_timestamp_worker} { system,
m_steady_clock_resource,
m_file_timestamp_worker} {
m_time_m = m_time_m =
system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
@ -99,7 +100,7 @@ TimeManager::TimeManager(Core::System& system)
m_set_sys = m_set_sys =
system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
res = MountTimeZoneBinary(system); res = m_time_zone_binary.Mount();
ASSERT(res == ResultSuccess); ASSERT(res == ResultSuccess);
m_worker.Initialize(m_time_sm, m_set_sys); m_worker.Initialize(m_time_sm, m_set_sys);
@ -187,10 +188,6 @@ TimeManager::TimeManager(Core::System& system)
} }
} }
TimeManager::~TimeManager() {
ResetTimeZoneBinary();
}
Result TimeManager::SetupStandardSteadyClockCore() { Result TimeManager::SetupStandardSteadyClockCore() {
Common::UUID external_clock_source_id{}; Common::UUID external_clock_source_id{};
auto res = m_set_sys->GetExternalSteadyClockSourceId(&external_clock_source_id); auto res = m_set_sys->GetExternalSteadyClockSourceId(&external_clock_source_id);
@ -236,7 +233,7 @@ Result TimeManager::SetupTimeZoneServiceCore() {
auto res = m_set_sys->GetDeviceTimeZoneLocationName(&name); auto res = m_set_sys->GetDeviceTimeZoneLocationName(&name);
ASSERT(res == ResultSuccess); ASSERT(res == ResultSuccess);
auto configured_zone = GetTimeZoneString(name); auto configured_zone = GetTimeZoneString(m_time_zone_binary, name);
if (configured_zone != name) { if (configured_zone != name) {
m_set_sys->SetDeviceTimeZoneLocationName(configured_zone); m_set_sys->SetDeviceTimeZoneLocationName(configured_zone);
@ -254,13 +251,13 @@ Result TimeManager::SetupTimeZoneServiceCore() {
res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(&time_point); res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(&time_point);
ASSERT(res == ResultSuccess); ASSERT(res == ResultSuccess);
auto location_count = GetTimeZoneCount(); auto location_count = m_time_zone_binary.GetTimeZoneCount();
Service::PSC::Time::RuleVersion rule_version{}; Service::PSC::Time::RuleVersion rule_version{};
GetTimeZoneVersion(rule_version); m_time_zone_binary.GetTimeZoneVersion(rule_version);
std::span<const u8> rule_buffer{}; std::span<const u8> rule_buffer{};
size_t rule_size{}; size_t rule_size{};
res = GetTimeZoneRule(rule_buffer, rule_size, name); res = m_time_zone_binary.GetTimeZoneRule(rule_buffer, rule_size, name);
ASSERT(res == ResultSuccess); ASSERT(res == ResultSuccess);
res = m_time_m->SetupTimeZoneServiceCore(name, rule_version, location_count, time_point, res = m_time_m->SetupTimeZoneServiceCore(name, rule_version, location_count, time_point,

View file

@ -10,6 +10,7 @@
#include "core/file_sys/vfs/vfs_types.h" #include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/service/glue/time/file_timestamp_worker.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/standard_steady_clock_resource.h"
#include "core/hle/service/glue/time/time_zone_binary.h"
#include "core/hle/service/glue/time/worker.h" #include "core/hle/service/glue/time/worker.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
@ -26,7 +27,7 @@ namespace Service::Glue::Time {
class TimeManager { class TimeManager {
public: public:
explicit TimeManager(Core::System& system); explicit TimeManager(Core::System& system);
~TimeManager(); ~TimeManager() = default;
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
@ -34,6 +35,7 @@ public:
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{}; std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{};
StandardSteadyClockResource m_steady_clock_resource; StandardSteadyClockResource m_steady_clock_resource;
FileTimestampWorker m_file_timestamp_worker; FileTimestampWorker m_file_timestamp_worker;
TimeZoneBinary m_time_zone_binary;
TimeWorker m_worker; TimeWorker m_worker;
private: private:

View file

@ -26,8 +26,9 @@ StaticService::StaticService(Core::System& system_,
std::shared_ptr<TimeManager> time, const char* name) std::shared_ptr<TimeManager> time, const char* name)
: ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m}, : 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_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{ m_file_timestamp_worker{time->m_file_timestamp_worker},
time->m_steady_clock_resource} { m_standard_steady_clock_resource{time->m_steady_clock_resource},
m_time_zone_binary{time->m_time_zone_binary} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, D<&StaticService::GetStandardUserSystemClock>, "GetStandardUserSystemClock"}, {0, D<&StaticService::GetStandardUserSystemClock>, "GetStandardUserSystemClock"},
@ -106,7 +107,7 @@ Result StaticService::GetTimeZoneService(OutInterface<TimeZoneService> out_servi
*out_service = std::make_shared<TimeZoneService>( *out_service = std::make_shared<TimeZoneService>(
m_system, m_file_timestamp_worker, m_setup_info.can_write_timezone_device_location, m_system, m_file_timestamp_worker, m_setup_info.can_write_timezone_device_location,
m_time_zone); m_time_zone_binary, m_time_zone);
R_SUCCEED(); R_SUCCEED();
} }

View file

@ -80,5 +80,6 @@ private:
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone; std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone;
FileTimestampWorker& m_file_timestamp_worker; FileTimestampWorker& m_file_timestamp_worker;
StandardSteadyClockResource& m_standard_steady_clock_resource; StandardSteadyClockResource& m_standard_steady_clock_resource;
TimeZoneBinary& m_time_zone_binary;
}; };
} // namespace Service::Glue::Time } // namespace Service::Glue::Time

View file

@ -15,19 +15,16 @@
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time { 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( TimeZoneService::TimeZoneService(
Core::System& system_, FileTimestampWorker& file_timestamp_worker, Core::System& system_, FileTimestampWorker& file_timestamp_worker,
bool can_write_timezone_device_location, bool can_write_timezone_device_location, TimeZoneBinary& time_zone_binary,
std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service) std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service)
: ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, : ServiceFramework{system_, "ITimeZoneService"}, m_system{system},
m_can_write_timezone_device_location{can_write_timezone_device_location}, m_can_write_timezone_device_location{can_write_timezone_device_location},
m_file_timestamp_worker{file_timestamp_worker}, m_file_timestamp_worker{file_timestamp_worker}, m_wrapped_service{std::move(
m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} { time_zone_service)},
m_operation_event{m_system}, m_time_zone_binary{time_zone_binary} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, D<&TimeZoneService::GetDeviceLocationName>, "GetDeviceLocationName"}, {0, D<&TimeZoneService::GetDeviceLocationName>, "GetDeviceLocationName"},
@ -48,7 +45,6 @@ TimeZoneService::TimeZoneService(
// clang-format on // clang-format on
RegisterHandlers(functions); RegisterHandlers(functions);
g_list_nodes.clear();
m_set_sys = m_set_sys =
m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
} }
@ -69,13 +65,13 @@ Result TimeZoneService::SetDeviceLocationName(
LOG_DEBUG(Service_Time, "called. location_name={}", location_name); LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound); R_UNLESS(m_time_zone_binary.IsValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound);
std::scoped_lock l{m_mutex}; std::scoped_lock l{m_mutex};
std::span<const u8> binary{}; std::span<const u8> binary{};
size_t binary_size{}; size_t binary_size{};
R_TRY(GetTimeZoneRule(binary, binary_size, location_name)) R_TRY(m_time_zone_binary.GetTimeZoneRule(binary, binary_size, location_name))
R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary)); R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary));
@ -88,8 +84,8 @@ Result TimeZoneService::SetDeviceLocationName(
m_set_sys->SetDeviceTimeZoneLocationName(name); m_set_sys->SetDeviceTimeZoneLocationName(name);
m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point); m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point);
std::scoped_lock m{g_list_mutex}; std::scoped_lock m{m_list_mutex};
for (auto& operation_event : g_list_nodes) { for (auto& operation_event : m_list_nodes) {
operation_event.m_event->Signal(); operation_event.m_event->Signal();
} }
R_SUCCEED(); R_SUCCEED();
@ -112,7 +108,8 @@ Result TimeZoneService::LoadLocationNameList(
}; };
std::scoped_lock l{m_mutex}; std::scoped_lock l{m_mutex};
R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index)); R_RETURN(
m_time_zone_binary.GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
} }
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
@ -122,7 +119,7 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
std::scoped_lock l{m_mutex}; std::scoped_lock l{m_mutex};
std::span<const u8> binary{}; std::span<const u8> binary{};
size_t binary_size{}; size_t binary_size{};
R_TRY(GetTimeZoneRule(binary, binary_size, name)) R_TRY(m_time_zone_binary.GetTimeZoneRule(binary, binary_size, name))
R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary)); R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary));
} }
@ -174,7 +171,7 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent"); m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent");
operation_event_initialized = true; operation_event_initialized = true;
std::scoped_lock l{m_mutex}; std::scoped_lock l{m_mutex};
g_list_nodes.push_back(m_operation_event); m_list_nodes.push_back(m_operation_event);
} }
*out_event = &m_operation_event.m_event->GetReadableEvent(); *out_event = &m_operation_event.m_event->GetReadableEvent();

View file

@ -32,6 +32,7 @@ class TimeZoneService;
namespace Service::Glue::Time { namespace Service::Glue::Time {
class FileTimestampWorker; class FileTimestampWorker;
class TimeZoneBinary;
class TimeZoneService final : public ServiceFramework<TimeZoneService> { class TimeZoneService final : public ServiceFramework<TimeZoneService> {
using InRule = InLargeData<Tz::Rule, BufferAttr_HipcMapAlias>; using InRule = InLargeData<Tz::Rule, BufferAttr_HipcMapAlias>;
@ -40,7 +41,7 @@ class TimeZoneService final : public ServiceFramework<TimeZoneService> {
public: public:
explicit TimeZoneService( explicit TimeZoneService(
Core::System& system, FileTimestampWorker& file_timestamp_worker, Core::System& system, FileTimestampWorker& file_timestamp_worker,
bool can_write_timezone_device_location, bool can_write_timezone_device_location, TimeZoneBinary& time_zone_binary,
std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service); std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service);
~TimeZoneService() override; ~TimeZoneService() override;
@ -85,6 +86,10 @@ private:
std::mutex m_mutex; std::mutex m_mutex;
bool operation_event_initialized{}; bool operation_event_initialized{};
Service::PSC::Time::OperationEvent m_operation_event; Service::PSC::Time::OperationEvent m_operation_event;
TimeZoneBinary& m_time_zone_binary;
std::mutex m_list_mutex;
Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType m_list_nodes{};
}; };
} // namespace Service::Glue::Time } // namespace Service::Glue::Time

View file

@ -12,18 +12,58 @@
#include "core/hle/service/glue/time/time_zone_binary.h" #include "core/hle/service/glue/time/time_zone_binary.h"
namespace Service::Glue::Time { namespace Service::Glue::Time {
namespace {
constexpr u64 TimeZoneBinaryId = 0x10000000000080E; constexpr u64 TimeZoneBinaryId = 0x10000000000080E;
static FileSys::VirtualDir g_time_zone_binary_romfs{}; void TimeZoneBinary::Reset() {
static Result g_time_zone_binary_mount_result{ResultUnknown}; time_zone_binary_romfs = {};
static std::vector<u8> g_time_zone_scratch_space(0x2800, 0); time_zone_binary_mount_result = ResultUnknown;
time_zone_scratch_space.clear();
time_zone_scratch_space.resize(0x2800, 0);
}
Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size, Result TimeZoneBinary::Mount() {
std::string_view path) { Reset();
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)}; 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);
if (nca) {
time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS());
}
if (time_zone_binary_romfs) {
// Validate that the romfs is readable, using invalid firmware keys can cause this to get
// set but the files to be garbage. In that case, we want to hit the next path and
// synthesise them instead.
time_zone_binary_mount_result = ResultSuccess;
Service::PSC::Time::LocationName name{"Etc/GMT"};
if (!IsValid(name)) {
Reset();
}
}
if (!time_zone_binary_romfs) {
time_zone_binary_romfs = FileSys::ExtractRomFS(
FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId));
}
R_UNLESS(time_zone_binary_romfs, ResultUnknown);
time_zone_binary_mount_result = ResultSuccess;
R_SUCCEED();
}
Result TimeZoneBinary::Read(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size,
std::string_view path) {
R_UNLESS(time_zone_binary_mount_result == ResultSuccess, time_zone_binary_mount_result);
auto vfs_file{time_zone_binary_romfs->GetFileRelative(path)};
R_UNLESS(vfs_file, ResultUnknown); R_UNLESS(vfs_file, ResultUnknown);
auto file_size{vfs_file->GetSize()}; auto file_size{vfs_file->GetSize()};
@ -36,82 +76,37 @@ Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_
R_SUCCEED(); R_SUCCEED();
} }
} // namespace
void ResetTimeZoneBinary() { void TimeZoneBinary::GetListPath(std::string& out_path) {
g_time_zone_binary_romfs = {}; if (time_zone_binary_mount_result != ResultSuccess) {
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) {
ResetTimeZoneBinary();
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);
if (nca) {
g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS());
}
if (g_time_zone_binary_romfs) {
// Validate that the romfs is readable, using invalid firmware keys can cause this to get
// set but the files to be garbage. In that case, we want to hit the next path and
// synthesise them instead.
g_time_zone_binary_mount_result = ResultSuccess;
Service::PSC::Time::LocationName name{"Etc/GMT"};
if (!IsTimeZoneBinaryValid(name)) {
ResetTimeZoneBinary();
}
}
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; return;
} }
// out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary"); // out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary");
out_path = "/binaryList.txt"; out_path = "/binaryList.txt";
} }
void GetTimeZoneBinaryVersionPath(std::string& out_path) { void TimeZoneBinary::GetVersionPath(std::string& out_path) {
if (g_time_zone_binary_mount_result != ResultSuccess) { if (time_zone_binary_mount_result != ResultSuccess) {
return; return;
} }
// out_path = fmt::format("{}:/version.txt", "TimeZoneBinary"); // out_path = fmt::format("{}:/version.txt", "TimeZoneBinary");
out_path = "/version.txt"; out_path = "/version.txt";
} }
void GetTimeZoneZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name) { void TimeZoneBinary::GetTimeZonePath(std::string& out_path,
if (g_time_zone_binary_mount_result != ResultSuccess) { const Service::PSC::Time::LocationName& name) {
if (time_zone_binary_mount_result != ResultSuccess) {
return; return;
} }
// out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name); // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name);
out_path = fmt::format("/zoneinfo/{}", name.data()); out_path = fmt::format("/zoneinfo/{}", name.data());
} }
bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name) { bool TimeZoneBinary::IsValid(const Service::PSC::Time::LocationName& name) {
std::string path{}; std::string path{};
GetTimeZoneZonePath(path, name); GetTimeZonePath(path, name);
auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; auto vfs_file{time_zone_binary_romfs->GetFileRelative(path)};
if (!vfs_file) { if (!vfs_file) {
LOG_INFO(Service_Time, "Could not find timezone file {}", path); LOG_INFO(Service_Time, "Could not find timezone file {}", path);
return false; return false;
@ -119,19 +114,19 @@ bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name) {
return vfs_file->GetSize() != 0; return vfs_file->GetSize() != 0;
} }
u32 GetTimeZoneCount() { u32 TimeZoneBinary::GetTimeZoneCount() {
std::string path{}; std::string path{};
GetTimeZoneBinaryListPath(path); GetListPath(path);
size_t bytes_read{}; size_t bytes_read{};
if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) { if (Read(bytes_read, time_zone_scratch_space, 0x2800, path) != ResultSuccess) {
return 0; return 0;
} }
if (bytes_read == 0) { if (bytes_read == 0) {
return 0; return 0;
} }
auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read); auto chars = std::span(reinterpret_cast<char*>(time_zone_scratch_space.data()), bytes_read);
u32 count{}; u32 count{};
for (auto chr : chars) { for (auto chr : chars) {
if (chr == '\n') { if (chr == '\n') {
@ -141,50 +136,47 @@ u32 GetTimeZoneCount() {
return count; return count;
} }
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) { Result TimeZoneBinary::GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
std::string path{}; std::string path{};
GetTimeZoneBinaryVersionPath(path); GetVersionPath(path);
auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version), auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version),
sizeof(Service::PSC::Time::RuleVersion))}; sizeof(Service::PSC::Time::RuleVersion))};
size_t bytes_read{}; size_t bytes_read{};
R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(), R_TRY(Read(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(), path));
path));
rule_version_buffer[bytes_read] = 0; rule_version_buffer[bytes_read] = 0;
R_SUCCEED(); R_SUCCEED();
} }
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, Result TimeZoneBinary::GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
const Service::PSC::Time::LocationName& name) { const Service::PSC::Time::LocationName& name) {
std::string path{}; std::string path{};
GetTimeZoneZonePath(path, name); GetTimeZonePath(path, name);
size_t bytes_read{}; size_t bytes_read{};
R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, R_TRY(Read(bytes_read, time_zone_scratch_space, time_zone_scratch_space.size(), path));
g_time_zone_scratch_space.size(), path));
out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read); out_rule = std::span(time_zone_scratch_space.data(), bytes_read);
out_rule_size = bytes_read; out_rule_size = bytes_read;
R_SUCCEED(); R_SUCCEED();
} }
Result GetTimeZoneLocationList(u32& out_count, Result TimeZoneBinary::GetTimeZoneLocationList(
std::span<Service::PSC::Time::LocationName> out_names, u32& out_count, std::span<Service::PSC::Time::LocationName> out_names, size_t max_names,
size_t max_names, u32 index) { u32 index) {
std::string path{}; std::string path{};
GetTimeZoneBinaryListPath(path); GetListPath(path);
size_t bytes_read{}; size_t bytes_read{};
R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, R_TRY(Read(bytes_read, time_zone_scratch_space, time_zone_scratch_space.size(), path));
g_time_zone_scratch_space.size(), path));
out_count = 0; out_count = 0;
R_SUCCEED_IF(bytes_read == 0); R_SUCCEED_IF(bytes_read == 0);
Service::PSC::Time::LocationName current_name{}; Service::PSC::Time::LocationName current_name{};
size_t current_name_len{}; size_t current_name_len{};
std::span<const u8> chars{g_time_zone_scratch_space}; std::span<const u8> chars{time_zone_scratch_space};
u32 name_count{}; u32 name_count{};
for (auto chr : chars) { for (auto chr : chars) {

View file

@ -6,6 +6,7 @@
#include <span> #include <span>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector>
#include "core/hle/service/psc/time/common.h" #include "core/hle/service/psc/time/common.h"
@ -15,18 +16,34 @@ class System;
namespace Service::Glue::Time { namespace Service::Glue::Time {
void ResetTimeZoneBinary(); class TimeZoneBinary {
Result MountTimeZoneBinary(Core::System& system); public:
void GetTimeZoneBinaryListPath(std::string& out_path); explicit TimeZoneBinary(Core::System& system_)
void GetTimeZoneBinaryVersionPath(std::string& out_path); : time_zone_scratch_space(0x2800, 0), system{system_} {}
void GetTimeZoneZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name);
bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name); Result Mount();
u32 GetTimeZoneCount(); bool IsValid(const Service::PSC::Time::LocationName& name);
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version); u32 GetTimeZoneCount();
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
const Service::PSC::Time::LocationName& name); Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
Result GetTimeZoneLocationList(u32& out_count, const Service::PSC::Time::LocationName& name);
std::span<Service::PSC::Time::LocationName> out_names, Result GetTimeZoneLocationList(u32& out_count,
size_t max_names, u32 index); std::span<Service::PSC::Time::LocationName> out_names,
size_t max_names, u32 index);
private:
void Reset();
Result Read(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size,
std::string_view path);
void GetListPath(std::string& out_path);
void GetVersionPath(std::string& out_path);
void GetTimeZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name);
FileSys::VirtualDir time_zone_binary_romfs{};
Result time_zone_binary_mount_result{ResultUnknown};
std::vector<u8> time_zone_scratch_space;
Core::System& system;
};
} // namespace Service::Glue::Time } // namespace Service::Glue::Time

View file

@ -16,23 +16,6 @@
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
namespace Service::Glue::Time { 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) {
T v{};
auto res = set_sys->GetSettingsItemValueImpl(v, category, name);
ASSERT(res == ResultSuccess);
return v;
}
} // namespace
TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
FileTimestampWorker& file_timestamp_worker) FileTimestampWorker& file_timestamp_worker)
@ -43,11 +26,6 @@ TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady
"Glue:TimeWorker:SteadyClockTimerEvent")}, "Glue:TimeWorker:SteadyClockTimerEvent")},
m_timer_file_system{m_ctx.CreateEvent("Glue:TimeWorker:FileTimeTimerEvent")}, m_timer_file_system{m_ctx.CreateEvent("Glue:TimeWorker:FileTimeTimerEvent")},
m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} { 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( m_timer_steady_clock_timing_event = Core::Timing::CreateEvent(
"Time::SteadyClockEvent", "Time::SteadyClockEvent",
[this](s64 time, [this](s64 time,
@ -82,6 +60,14 @@ TimeWorker::~TimeWorker() {
m_ctx.CloseEvent(m_timer_file_system); m_ctx.CloseEvent(m_timer_file_system);
} }
template <typename T>
T TimeWorker::GetSettingsItemValue(const std::string& category, const std::string& name) {
T v{};
auto res = m_set_sys->GetSettingsItemValueImpl(v, category, name);
ASSERT(res == ResultSuccess);
return v;
}
void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) { std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) {
m_set_sys = std::move(set_sys); m_set_sys = std::move(set_sys);
@ -91,8 +77,8 @@ void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> t
m_alarm_worker.Initialize(m_time_m); m_alarm_worker.Initialize(m_time_m);
auto steady_clock_interval_m = GetSettingsItemValue<s32>( auto steady_clock_interval_m =
m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes"); GetSettingsItemValue<s32>("time", "standard_steady_clock_rtc_update_interval_minutes");
auto one_minute_ns{ auto one_minute_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
@ -102,8 +88,7 @@ void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> t
std::chrono::nanoseconds(steady_clock_interval_ns), std::chrono::nanoseconds(steady_clock_interval_ns),
m_timer_steady_clock_timing_event); m_timer_steady_clock_timing_event);
auto fs_notify_time_s = auto fs_notify_time_s = GetSettingsItemValue<s32>("time", "notify_time_to_fs_interval_seconds");
GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds");
auto one_second_ns{ auto one_second_ns{
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns}; s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns};
@ -218,14 +203,14 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
} }
[[maybe_unused]] auto offset_before{ [[maybe_unused]] auto offset_before{
g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0}; m_ig_report_network_clock_context_set ? m_report_network_clock_context.offset : 0};
// TODO system report "standard_netclock_operation" // TODO system report "standard_netclock_operation"
// "clock_time" = time // "clock_time" = time
// "context_offset_before" = offset_before // "context_offset_before" = offset_before
// "context_offset_after" = context.offset // "context_offset_after" = context.offset
g_report_network_clock_context = context; m_report_network_clock_context = context;
if (!g_ig_report_network_clock_context_set) { if (!m_ig_report_network_clock_context_set) {
g_ig_report_network_clock_context_set = true; m_ig_report_network_clock_context_set = true;
} }
m_file_timestamp_worker.SetFilesystemPosixTime(); m_file_timestamp_worker.SetFilesystemPosixTime();
@ -247,16 +232,16 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
break; break;
} }
[[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set [[maybe_unused]] auto offset_before{m_ig_report_ephemeral_clock_context_set
? g_report_ephemeral_clock_context.offset ? m_report_ephemeral_clock_context.offset
: 0}; : 0};
// TODO system report "ephemeral_netclock_operation" // TODO system report "ephemeral_netclock_operation"
// "clock_time" = time // "clock_time" = time
// "context_offset_before" = offset_before // "context_offset_before" = offset_before
// "context_offset_after" = context.offset // "context_offset_after" = context.offset
g_report_ephemeral_clock_context = context; m_report_ephemeral_clock_context = context;
if (!g_ig_report_ephemeral_clock_context_set) { if (!m_ig_report_ephemeral_clock_context_set) {
g_ig_report_ephemeral_clock_context_set = true; m_ig_report_ephemeral_clock_context_set = true;
} }
break; break;
} }

View file

@ -34,6 +34,9 @@ public:
void StartThread(); void StartThread();
private: private:
template <typename T>
T GetSettingsItemValue(const std::string& category, const std::string& name);
void ThreadFunc(std::stop_token stop_token); void ThreadFunc(std::stop_token stop_token);
Core::System& m_system; Core::System& m_system;
@ -59,6 +62,11 @@ private:
std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event; std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event;
AlarmWorker m_alarm_worker; AlarmWorker m_alarm_worker;
PmStateChangeHandler m_pm_state_change_handler; PmStateChangeHandler m_pm_state_change_handler;
bool m_ig_report_network_clock_context_set{};
Service::PSC::Time::SystemClockContext m_report_network_clock_context{};
bool m_ig_report_ephemeral_clock_context_set{};
Service::PSC::Time::SystemClockContext m_report_ephemeral_clock_context{};
}; };
} // namespace Service::Glue::Time } // namespace Service::Glue::Time

View file

@ -71,7 +71,7 @@ const char* GetType(GLenum type) {
void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void* user_param) { const GLchar* message, const void* user_param) {
const char format[] = "{} {} {}: {}"; constexpr std::string_view format = "{} {} {}: {}";
const char* const str_source = GetSource(source); const char* const str_source = GetSource(source);
const char* const str_type = GetType(type); const char* const str_type = GetType(type);