From 0c60930e33e0888d98b9d6770cf6397d4a711c27 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 16 Mar 2020 13:08:20 -0700 Subject: [PATCH] os: add rngmanager --- .../source/os/impl/os_resource_manager.hpp | 3 ++ .../source/os/impl/os_rng_manager.hpp | 25 ++++++++++++ .../source/os/impl/os_rng_manager_impl.cpp | 31 +++++++++++++++ .../source/os/impl/os_rng_manager_impl.hpp | 34 +++++++++++++++++ .../impl/os_rng_manager_impl.os.horizon.cpp | 38 +++++++++++++++++++ libstratosphere/source/os/os_random.cpp | 2 +- 6 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 libstratosphere/source/os/impl/os_rng_manager.hpp create mode 100644 libstratosphere/source/os/impl/os_rng_manager_impl.cpp create mode 100644 libstratosphere/source/os/impl/os_rng_manager_impl.hpp create mode 100644 libstratosphere/source/os/impl/os_rng_manager_impl.os.horizon.cpp diff --git a/libstratosphere/source/os/impl/os_resource_manager.hpp b/libstratosphere/source/os/impl/os_resource_manager.hpp index 4129a884..61525e90 100644 --- a/libstratosphere/source/os/impl/os_resource_manager.hpp +++ b/libstratosphere/source/os/impl/os_resource_manager.hpp @@ -15,18 +15,21 @@ */ #pragma once #include +#include "os_rng_manager_impl.hpp" #include "os_tick_manager_impl.hpp" namespace ams::os::impl { class OsResourceManager { private: + RngManager rng_manager{}; /* TODO */ TickManager tick_manager{}; /* TODO */ public: constexpr OsResourceManager() = default; + constexpr ALWAYS_INLINE RngManager &GetRngManager() { return this->rng_manager; } constexpr ALWAYS_INLINE TickManager &GetTickManager() { return this->tick_manager; } }; diff --git a/libstratosphere/source/os/impl/os_rng_manager.hpp b/libstratosphere/source/os/impl/os_rng_manager.hpp new file mode 100644 index 00000000..7abc003f --- /dev/null +++ b/libstratosphere/source/os/impl/os_rng_manager.hpp @@ -0,0 +1,25 @@ +/* + * 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 { + + ALWAYS_INLINE RngManager &GetRngManager() { + return GetResourceManager().GetRngManager(); + } + +} diff --git a/libstratosphere/source/os/impl/os_rng_manager_impl.cpp b/libstratosphere/source/os/impl/os_rng_manager_impl.cpp new file mode 100644 index 00000000..21edde42 --- /dev/null +++ b/libstratosphere/source/os/impl/os_rng_manager_impl.cpp @@ -0,0 +1,31 @@ +/* + * 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_rng_manager_impl.hpp" + +namespace ams::os::impl { + + u64 RngManager::GenerateRandomU64() { + std::scoped_lock lk(this->lock); + + if (AMS_UNLIKELY(!this->initialized)) { + this->Initialize(); + } + + return this->mt.GenerateRandomU64(); + } + +} diff --git a/libstratosphere/source/os/impl/os_rng_manager_impl.hpp b/libstratosphere/source/os/impl/os_rng_manager_impl.hpp new file mode 100644 index 00000000..25406633 --- /dev/null +++ b/libstratosphere/source/os/impl/os_rng_manager_impl.hpp @@ -0,0 +1,34 @@ +/* + * 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 RngManager { + private: + util::TinyMT mt; + os::Mutex lock; + bool initialized; + private: + void Initialize(); + public: + constexpr RngManager() : mt(), lock(), initialized() { /* ... */ } + public: + u64 GenerateRandomU64(); + }; + +} diff --git a/libstratosphere/source/os/impl/os_rng_manager_impl.os.horizon.cpp b/libstratosphere/source/os/impl/os_rng_manager_impl.os.horizon.cpp new file mode 100644 index 00000000..84a350c3 --- /dev/null +++ b/libstratosphere/source/os/impl/os_rng_manager_impl.os.horizon.cpp @@ -0,0 +1,38 @@ +/* + * 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_rng_manager_impl.hpp" + +namespace ams::os::impl { + + void RngManager::Initialize() { + /* Retrieve entropy from kernel. */ + u32 seed[4]; + static_assert(util::size(seed) == util::TinyMT::NumStateWords); + + /* Nintendo does not check the result of these invocations, but we will for safety. */ + /* Nintendo uses entropy values 0, 1 to seed the public TinyMT random, and values */ + /* 2, 3 to seed os::detail::RngManager's private TinyMT random. */ + R_ABORT_UNLESS(svcGetInfo(reinterpret_cast(&seed[0]), InfoType_RandomEntropy, INVALID_HANDLE, 2)); + R_ABORT_UNLESS(svcGetInfo(reinterpret_cast(&seed[2]), InfoType_RandomEntropy, INVALID_HANDLE, 3)); + + this->mt.Initialize(seed, util::size(seed)); + + /* Note that we've initialized. */ + this->initialized = true; + } + +} diff --git a/libstratosphere/source/os/os_random.cpp b/libstratosphere/source/os/os_random.cpp index 3498b14a..cd3962d2 100644 --- a/libstratosphere/source/os/os_random.cpp +++ b/libstratosphere/source/os/os_random.cpp @@ -42,7 +42,7 @@ namespace ams::os { void GenerateRandomBytes(void *dst, size_t size) { std::scoped_lock lk(g_random_mutex); - if (!g_initialized_random) { + if (AMS_UNLIKELY(!g_initialized_random)) { impl::InitializeRandomImpl(&g_random); g_initialized_random = true; }