diff --git a/exosphere2/program/source/smc/secmon_random_cache.cpp b/exosphere2/program/source/smc/secmon_random_cache.cpp index 13b1fd941..f14330b93 100644 --- a/exosphere2/program/source/smc/secmon_random_cache.cpp +++ b/exosphere2/program/source/smc/secmon_random_cache.cpp @@ -21,8 +21,6 @@ namespace ams::secmon::smc { namespace { - constexpr inline size_t MaxRandomBytes = sizeof(SmcArguments) - sizeof(SmcArguments{}.r[0]); - constinit int g_random_offset_low = 0; constinit int g_random_offset_high = 0; diff --git a/exosphere2/program/source/smc/secmon_random_cache.hpp b/exosphere2/program/source/smc/secmon_random_cache.hpp index f3cbdc731..e1e00825c 100644 --- a/exosphere2/program/source/smc/secmon_random_cache.hpp +++ b/exosphere2/program/source/smc/secmon_random_cache.hpp @@ -19,6 +19,8 @@ namespace ams::secmon::smc { + constexpr inline size_t MaxRandomBytes = sizeof(SmcArguments) - sizeof(SmcArguments{}.r[0]); + void FillRandomCache(); void RefillRandomCache(); void GetRandomFromCache(void *dst, size_t size); diff --git a/exosphere2/program/source/smc/secmon_smc_common.hpp b/exosphere2/program/source/smc/secmon_smc_common.hpp index dba7c4af5..861acca26 100644 --- a/exosphere2/program/source/smc/secmon_smc_common.hpp +++ b/exosphere2/program/source/smc/secmon_smc_common.hpp @@ -22,7 +22,7 @@ namespace ams::secmon::smc { Success = 0, NotImplemented = 1, InvalidArgument = 2, - InProgress = 3, + Busy = 3, NoAsyncOperation = 4, InvalidAsyncOperation = 5, NotPermitted = 6, diff --git a/exosphere2/program/source/smc/secmon_smc_random.cpp b/exosphere2/program/source/smc/secmon_smc_random.cpp index 693080aa7..d057d27d5 100644 --- a/exosphere2/program/source/smc/secmon_smc_random.cpp +++ b/exosphere2/program/source/smc/secmon_smc_random.cpp @@ -16,17 +16,69 @@ #include #include "../secmon_error.hpp" #include "secmon_smc_random.hpp" +#include "secmon_random_cache.hpp" +#include "secmon_smc_se_lock.hpp" namespace ams::secmon::smc { + namespace { + + SmcResult GenerateRandomBytesImpl(SmcArguments &args) { + /* Validate the input size. */ + const size_t size = args.r[1]; + + if (size > MaxRandomBytes) { + return SmcResult::InvalidArgument; + } + + /* Create a buffer that the se can generate bytes into. */ + util::AlignedBuffer buffer; + hw::FlushDataCache(buffer, size); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Generate random bytes into the buffer. */ + se::GenerateRandomBytes(buffer, size); + + /* Ensure that the cpu sees consistent data. */ + hw::DataSynchronizationBarrierInnerShareable(); + hw::FlushDataCache(buffer, size); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Copy the bytes to output. */ + std::memcpy(std::addressof(args.r[1]), buffer, size); + return SmcResult::Success; + } + + } + SmcResult SmcGenerateRandomBytes(SmcArguments &args) { - /* TODO */ - return SmcResult::NotImplemented; + return LockSecurityEngineAndInvoke(args, GenerateRandomBytesImpl); } SmcResult SmcGenerateRandomBytesNonBlocking(SmcArguments &args) { - /* TODO */ - return SmcResult::NotImplemented; + /* Try to lock the security engine, so that we can call the standard impl. */ + if (TryLockSecurityEngine()) { + /* Ensure we unlock the security engine when done. */ + ON_SCOPE_EXIT { UnlockSecurityEngine(); }; + + /* Take advantage of our lock to refill lthe random cache. */ + ON_SCOPE_EXIT { RefillRandomCache(); }; + + /* If we lock it successfully, we can just call the blocking impl. */ + return GenerateRandomBytesImpl(args); + } else { + /* Otherwise, we'll retrieve some bytes from the cache. */ + const size_t size = args.r[1]; + + /* Validate the input size. */ + if (size > MaxRandomBytes) { + return SmcResult::InvalidArgument; + } + + /* Get random bytes from the cache. */ + GetRandomFromCache(std::addressof(args.r[1]), size); + return SmcResult::Success; + } } } diff --git a/exosphere2/program/source/smc/secmon_smc_se_lock.cpp b/exosphere2/program/source/smc/secmon_smc_se_lock.cpp index d748ce70a..63b662282 100644 --- a/exosphere2/program/source/smc/secmon_smc_se_lock.cpp +++ b/exosphere2/program/source/smc/secmon_smc_se_lock.cpp @@ -38,4 +38,41 @@ namespace ams::secmon::smc { return g_is_locked; } + SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl) { + /* Try to lock the SE. */ + if (!TryLockSecurityEngine()) { + return SmcResult::Busy; + } + ON_SCOPE_EXIT { UnlockSecurityEngine(); }; + + return impl(args); + } + + SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler) { + SmcResult result = SmcResult::Busy; + + /* Try to lock the security engine. */ + if (TryLockSecurityEngine()) { + /* Try to start an async operation. */ + if (const u64 async_key = BeginAsyncOperation(result_handler); async_key != InvalidAsyncKey) { + /* Invoke the operation. */ + result = impl(args); + + /* If the operation was successful, return the key. */ + if (result == SmcResult::Success) { + args.r[1] = async_key; + return SmcResult::Success; + } + + /* Otherwise, cancel the async operation. */ + CancelAsyncOperation(async_key); + } + + /* We failed to invoke the async op, so unlock the security engine. */ + UnlockSecurityEngine(); + } + + return result; + } + } diff --git a/exosphere2/program/source/smc/secmon_smc_se_lock.hpp b/exosphere2/program/source/smc/secmon_smc_se_lock.hpp index db8e62cf0..d7fc33d7d 100644 --- a/exosphere2/program/source/smc/secmon_smc_se_lock.hpp +++ b/exosphere2/program/source/smc/secmon_smc_se_lock.hpp @@ -16,6 +16,8 @@ #pragma once #include #include "secmon_smc_common.hpp" +#include "secmon_smc_handler.hpp" +#include "secmon_smc_result.hpp" namespace ams::secmon::smc { @@ -23,4 +25,7 @@ namespace ams::secmon::smc { void UnlockSecurityEngine(); bool IsSecurityEngineLocked(); + SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl); + SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler); + }