From 43bd733f0a8ecdec0108a9bdf9a8ee18ca02ae82 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 16 Mar 2020 01:02:55 -0700 Subject: [PATCH] os: implement Tick api, make build with -Werror --- .../include/stratosphere/fs/fs_substorage.hpp | 8 +- .../include/stratosphere/os.hpp | 1 + .../include/stratosphere/os/os_tick.hpp | 70 ++++++++++++++++ .../source/kvdb/kvdb_file_key_value_store.cpp | 2 +- .../source/os/impl/os_resource_manager.cpp | 24 ++++++ .../source/os/impl/os_resource_manager.hpp | 48 +++++++++++ .../source/os/impl/os_tick_manager.hpp | 30 +++++++ .../source/os/impl/os_tick_manager_impl.cpp | 84 +++++++++++++++++++ .../source/os/impl/os_tick_manager_impl.hpp | 56 +++++++++++++ .../impl/os_tick_manager_impl.os.horizon.hpp | 46 ++++++++++ .../libstratosphere/source/os/os_tick.cpp | 37 ++++++++ .../source/patcher/patcher_api.cpp | 3 + .../source/updater/updater_api.cpp | 2 +- 13 files changed, 405 insertions(+), 6 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_tick.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_resource_manager.cpp create mode 100644 libraries/libstratosphere/source/os/impl/os_resource_manager.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_tick_manager.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_tick_manager_impl.cpp create mode 100644 libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.horizon.hpp create mode 100644 libraries/libstratosphere/source/os/os_tick.cpp diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp index 9470b4747..4e39ae361 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp @@ -33,7 +33,7 @@ namespace ams::fs { public: SubStorage() : shared_base_storage(), base_storage(nullptr), offset(0), size(0), resizable(false) { /* ... */ } - SubStorage(const SubStorage &rhs) : shared_base_storage(), base_storage(rhs.base_storage), offset(rhs.offset), size(rhs.size), resizable(rhs.resizable) { /* ... */} + SubStorage(const SubStorage &rhs) : shared_base_storage(), base_storage(rhs.base_storage), offset(rhs.offset), size(rhs.size), resizable(rhs.resizable) { /* ... */} SubStorage &operator=(const SubStorage &rhs) { if (this != std::addressof(rhs)) { this->base_storage = rhs.base_storage; @@ -44,19 +44,19 @@ namespace ams::fs { return *this; } - SubStorage(IStorage *storage, s64 o, s64 sz) : shared_base_storage(), base_storage(storage), offset(o), size(sz) { + SubStorage(IStorage *storage, s64 o, s64 sz) : shared_base_storage(), base_storage(storage), offset(o), size(sz), resizable(false) { AMS_ABORT_UNLESS(this->IsValid()); AMS_ABORT_UNLESS(this->offset >= 0); AMS_ABORT_UNLESS(this->size >= 0); } - SubStorage(std::shared_ptr storage, s64 o, s64 sz) : shared_base_storage(storage), base_storage(storage.get()), offset(o), size(sz) { + SubStorage(std::shared_ptr storage, s64 o, s64 sz) : shared_base_storage(storage), base_storage(storage.get()), offset(o), size(sz), resizable(false) { AMS_ABORT_UNLESS(this->IsValid()); AMS_ABORT_UNLESS(this->offset >= 0); AMS_ABORT_UNLESS(this->size >= 0); } - SubStorage(SubStorage *sub, s64 o, s64 sz) : shared_base_storage(), base_storage(sub->base_storage), offset(o + sub->offset), size(sz) { + SubStorage(SubStorage *sub, s64 o, s64 sz) : shared_base_storage(), base_storage(sub->base_storage), offset(o + sub->offset), size(sz), resizable(false) { AMS_ABORT_UNLESS(this->IsValid()); AMS_ABORT_UNLESS(this->offset >= 0); AMS_ABORT_UNLESS(this->size >= 0); diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 3ac4ef904..abd5e77d2 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -18,6 +18,7 @@ #include "os/os_common_types.hpp" #include "os/os_memory_common.hpp" +#include "os/os_tick.hpp" #include "os/os_managed_handle.hpp" #include "os/os_process_handle.hpp" #include "os/os_random.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/os/os_tick.hpp b/libraries/libstratosphere/include/stratosphere/os/os_tick.hpp new file mode 100644 index 000000000..67d42b585 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_tick.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_common_types.hpp" + +namespace ams::os { + + class Tick; + + /* Tick API. */ + Tick GetSystemTick(); + s64 GetSystemTickFrequency(); + TimeSpan ConvertToTimeSpan(Tick tick); + Tick ConvertToTick(TimeSpan ts); + + class Tick { + private: + s64 tick; + public: + constexpr explicit Tick(s64 t = 0) : tick(t) { /* ... */ } + Tick(TimeSpan ts) : tick(ConvertToTick(ts).GetInt64Value()) { /* ... */ } + public: + constexpr s64 GetInt64Value() const { return this->tick; } + TimeSpan ToTimeSpan() const { return ConvertToTimeSpan(*this); } + + /* Tick arithmetic. */ + constexpr Tick &operator+=(Tick rhs) { this->tick += rhs.tick; return *this; } + constexpr Tick &operator-=(Tick rhs) { this->tick -= rhs.tick; return *this; } + constexpr Tick operator+(Tick rhs) const { Tick r(*this); return r += rhs; } + constexpr Tick operator-(Tick rhs) const { Tick r(*this); return r -= rhs; } + + constexpr bool operator==(const Tick &rhs) const { + return this->tick == rhs.tick; + } + + constexpr bool operator!=(const Tick &rhs) const { + return !(*this == rhs); + } + + constexpr bool operator<(const Tick &rhs) const { + return this->tick < rhs.tick; + } + + constexpr bool operator>=(const Tick &rhs) const { + return !(*this < rhs); + } + + constexpr bool operator>(const Tick &rhs) const { + return this->tick > rhs.tick; + } + + constexpr bool operator<=(const Tick &rhs) const { + return !(*this > rhs); + } + }; + +} diff --git a/libraries/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp b/libraries/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp index 540ef3608..eb699b600 100644 --- a/libraries/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp +++ b/libraries/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp @@ -222,7 +222,7 @@ namespace ams::kvdb { R_UNLESS(file_size <= static_cast(max_out_size), ResultBufferInsufficient()); /* Read the value. */ - const size_t value_size = static_cast(value_size); + const size_t value_size = static_cast(file_size); R_TRY(fs::ReadFile(file, 0, out_value, value_size)); *out_size = value_size; diff --git a/libraries/libstratosphere/source/os/impl/os_resource_manager.cpp b/libraries/libstratosphere/source/os/impl/os_resource_manager.cpp new file mode 100644 index 000000000..539f9e178 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_resource_manager.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "os_resource_manager.hpp" + +namespace ams::os::impl { + + /* TODO: C++20 constinit */ + OsResourceManager ResourceManagerHolder::s_resource_manager = {}; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp new file mode 100644 index 000000000..4129a8846 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "os_tick_manager_impl.hpp" + +namespace ams::os::impl { + + class OsResourceManager { + private: + /* TODO */ + TickManager tick_manager{}; + /* TODO */ + public: + constexpr OsResourceManager() = default; + + constexpr ALWAYS_INLINE TickManager &GetTickManager() { return this->tick_manager; } + }; + + class ResourceManagerHolder { + private: + static /* TODO: C++20 constinit */ OsResourceManager s_resource_manager; + private: + constexpr ResourceManagerHolder() { /* ... */ } + public: + static ALWAYS_INLINE OsResourceManager &GetResourceManagerInstance() { + return s_resource_manager; + } + }; + + ALWAYS_INLINE OsResourceManager &GetResourceManager() { + return ResourceManagerHolder::GetResourceManagerInstance(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager.hpp b/libraries/libstratosphere/source/os/impl/os_tick_manager.hpp new file mode 100644 index 000000000..69a8a5ee7 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "os_resource_manager.hpp" + +namespace ams::os::impl { + + ALWAYS_INLINE TickManager &GetTickManager() { + return GetResourceManager().GetTickManager(); + } + + ALWAYS_INLINE Tick GetCurrentTick() { + return GetTickManager().GetTick(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.cpp b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.cpp new file mode 100644 index 000000000..209cc9848 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "os_tick_manager.hpp" + +namespace ams::os::impl { + + TimeSpan TickManager::ConvertToTimeSpan(Tick tick) const { + /* Get the tick value. */ + const s64 tick_val = tick.GetInt64Value(); + + /* Get the tick frequency. */ + const s64 tick_freq = GetTickFrequency(); + AMS_AUDIT(tick_freq < MaxTickFrequency); + + /* Clamp tick to range. */ + if (tick_val > GetMaxTick()) { + return TimeSpan::FromNanoSeconds(std::numeric_limits::max()); + } else if (tick_val < -GetMaxTick()) { + return TimeSpan::FromNanoSeconds(std::numeric_limits::min()); + } else { + /* Convert to timespan. */ + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + const s64 seconds = tick_val / tick_freq; + const s64 frac = tick_val % tick_freq; + const TimeSpan ts = TimeSpan::FromSeconds(seconds) + TimeSpan::FromNanoSeconds(frac * NanoSecondsPerSecond / tick_freq); + + constexpr TimeSpan ZeroTS = TimeSpan::FromNanoSeconds(0); + AMS_ASSERT(!((tick_val > 0 && ts < ZeroTS) || (tick_val < 0 && ts > ZeroTS))); + + return ts; + } + } + + Tick TickManager::ConvertToTick(TimeSpan ts) const { + /* Get the TimeSpan in nanoseconds. */ + const s64 ns = ts.GetNanoSeconds(); + + /* Clamp ns to range. */ + if (ns > GetMaxTimeSpanNs()) { + return Tick(std::numeric_limits::max()); + } else if (ns < -GetMaxTimeSpanNs()) { + return Tick(std::numeric_limits::min()); + } else { + /* Get the tick frequency. */ + const s64 tick_freq = GetTickFrequency(); + AMS_AUDIT(tick_freq < MaxTickFrequency); + + /* Convert to tick. */ + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + const bool negative = ns < 0; + s64 seconds = ns / NanoSecondsPerSecond; + s64 frac = ns % NanoSecondsPerSecond; + + /* If negative, negate seconds/frac. */ + if (negative) { + seconds = -seconds; + frac = -frac; + } + + /* Calculate the tick, and invert back to negative if needed. */ + s64 tick = (seconds * tick_freq) + ((frac * tick_freq + NanoSecondsPerSecond - 1) / NanoSecondsPerSecond); + if (negative) { + tick = -tick; + } + + return Tick(tick); + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp new file mode 100644 index 000000000..eda9cb7cc --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#ifdef ATMOSPHERE_OS_HORIZON + #include "os_tick_manager_impl.os.horizon.hpp" +#else + #error "Unknown OS for TickManagerImpl" +#endif + +namespace ams::os::impl { + + /* Tick frequency must be less than INT64_MAX / 1 second. */ + static constexpr s64 MaxTickFrequency = (std::numeric_limits::max() / TimeSpan::FromSeconds(1).GetNanoSeconds()) - 1; + + class TickManager { + private: + TickManagerImpl impl; + public: + constexpr TickManager() : impl() { /* ... */ } + + ALWAYS_INLINE Tick GetTick() const { + return this->impl.GetTick(); + } + + ALWAYS_INLINE s64 GetTickFrequency() const { + return this->impl.GetTickFrequency(); + } + + ALWAYS_INLINE s64 GetMaxTick() const { + return this->impl.GetMaxTick(); + } + + ALWAYS_INLINE s64 GetMaxTimeSpanNs() const { + return this->impl.GetMaxTimeSpanNs(); + } + + TimeSpan ConvertToTimeSpan(Tick tick) const; + Tick ConvertToTick(TimeSpan ts) const; + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.horizon.hpp new file mode 100644 index 000000000..3a9301cdc --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.horizon.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class TickManagerImpl { + public: + constexpr TickManagerImpl() { /* ... */ } + + ALWAYS_INLINE Tick GetTick() const { + s64 tick; + __asm__ __volatile__("mrs %[tick], cntpct_el0" : [tick]"=&r"(tick) :: "memory"); + return Tick(tick); + } + + static constexpr ALWAYS_INLINE s64 GetTickFrequency() { + return static_cast(::ams::svc::TicksPerSecond); + } + + static constexpr ALWAYS_INLINE s64 GetMaxTick() { + static_assert(GetTickFrequency() <= TimeSpan::FromSeconds(1).GetNanoSeconds()); + return (std::numeric_limits::max() / TimeSpan::FromSeconds(1).GetNanoSeconds()) * GetTickFrequency(); + } + + static constexpr ALWAYS_INLINE s64 GetMaxTimeSpanNs() { + static_assert(GetTickFrequency() <= TimeSpan::FromSeconds(1).GetNanoSeconds()); + return TimeSpan::FromNanoSeconds(std::numeric_limits::max()).GetNanoSeconds(); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/os_tick.cpp b/libraries/libstratosphere/source/os/os_tick.cpp new file mode 100644 index 000000000..71804c35e --- /dev/null +++ b/libraries/libstratosphere/source/os/os_tick.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_tick_manager.hpp" + +namespace ams::os { + + Tick GetSystemTick() { + return impl::GetTickManager().GetTick(); + } + + s64 GetSystemTickFrequency() { + return impl::GetTickManager().GetTickFrequency(); + } + + TimeSpan ConvertToTimeSpan(Tick tick) { + return impl::GetTickManager().ConvertToTimeSpan(tick); + } + + Tick ConvertToTick(TimeSpan ts) { + return impl::GetTickManager().ConvertToTick(ts); + } + +} diff --git a/libraries/libstratosphere/source/patcher/patcher_api.cpp b/libraries/libstratosphere/source/patcher/patcher_api.cpp index f4056190a..74c7637fb 100644 --- a/libraries/libstratosphere/source/patcher/patcher_api.cpp +++ b/libraries/libstratosphere/source/patcher/patcher_api.cpp @@ -237,7 +237,10 @@ namespace ams::patcher { } /* Print the path for this directory. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation" std::snprintf(path + patches_dir_path_len, sizeof(path) - patches_dir_path_len, "/%s", entry.name); +#pragma GCC diagnostic pop const size_t patch_dir_path_len = patches_dir_path_len + 1 + std::strlen(entry.name); /* Open the patch directory. */ diff --git a/libraries/libstratosphere/source/updater/updater_api.cpp b/libraries/libstratosphere/source/updater/updater_api.cpp index 55551c7e4..ec978113f 100644 --- a/libraries/libstratosphere/source/updater/updater_api.cpp +++ b/libraries/libstratosphere/source/updater/updater_api.cpp @@ -115,7 +115,7 @@ namespace ams::updater { Result VerifyBootImagesAndRepairIfNeeded(bool *out_repaired, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type) { /* Get system data id for boot images (819/81A/81B/81C). */ - ncm::SystemDataId bip_data_id; + ncm::SystemDataId bip_data_id = {}; R_TRY(GetBootImagePackageId(&bip_data_id, mode, work_buffer, work_buffer_size)); /* Verify the boot images in NAND. */