diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp index 7f9397d6f..db2842e1b 100644 --- a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp @@ -147,6 +147,13 @@ namespace ams::kern::svc { if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_QueryIoMapping, LegacyQueryIoMapping::Call64From32); } } + /* 6.0.0 broke the ABI for GetFutureThreadInfo, and renamed it to GetDebugFutureThreadInfo. */ + if (target_fw < TargetFirmware_6_0_0) { + static_assert(svc::SvcId_GetDebugFutureThreadInfo == svc::SvcId_LegacyGetFutureThreadInfo); + if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_GetDebugFutureThreadInfo, LegacyGetFutureThreadInfo::Call64); } + if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_GetDebugFutureThreadInfo, LegacyGetFutureThreadInfo::Call64From32); } + } + /* 3.0.0 broke the ABI for ContinueDebugEvent. */ if (target_fw < TargetFirmware_3_0_0) { if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_ContinueDebugEvent, LegacyContinueDebugEvent::Call64); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_thread_profiler.cpp b/libraries/libmesosphere/source/svc/kern_svc_thread_profiler.cpp index fd968bd30..0f29b5668 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_thread_profiler.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_thread_profiler.cpp @@ -21,6 +21,56 @@ namespace ams::kern::svc { namespace { + Result GetLastThreadInfoImpl(ams::svc::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags) { + /* Disable interrupts. */ + KScopedInterruptDisable di; + + /* Get the previous thread. */ + KThread *prev_thread = Kernel::GetScheduler().GetPreviousThread(); + R_UNLESS(prev_thread != nullptr, svc::ResultNoThread()); + + /* Verify the last thread was owned by the current process. */ + R_UNLESS(prev_thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultUnknownThread()); + + /* Clear the output flags. */ + *out_flags = 0; + + /* Get the thread's exception context. */ + GetExceptionContext(prev_thread)->GetSvcThreadContext(out_context); + + /* Get the tls address. */ + *out_tls_address = GetInteger(prev_thread->GetThreadLocalRegionAddress()); + + /* Set the syscall flag if appropriate. */ + if (prev_thread->IsCallingSvc()) { + *out_flags |= ams::svc::LastThreadInfoFlag_ThreadInSystemCall; + } + + return ResultSuccess(); + } + + Result SynchronizeCurrentProcessToFutureTime(int64_t ns) { + /* Get the wait object. */ + KWaitObject *wait_object = GetCurrentProcess().GetWaitObjectPointer(); + + /* Convert the timeout from nanoseconds to ticks. */ + s64 timeout; + if (ns > 0) { + u64 ticks = KHardwareTimer::GetTick(); + ticks += ams::svc::Tick(TimeSpan::FromNanoSeconds(ns)); + ticks += 2; + + timeout = ticks; + } else { + timeout = ns; + } + + /* Synchronize to the desired time. */ + R_TRY(wait_object->Synchronize(timeout)); + + return ResultSuccess(); + } + Result GetDebugFutureThreadInfo(ams::svc::LastThreadContext *out_context, uint64_t *out_thread_id, ams::svc::Handle debug_handle, int64_t ns) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNoThread()); @@ -30,25 +80,7 @@ namespace ams::kern::svc { R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Synchronize the current process to the desired time. */ - { - /* Get the wait object. */ - KWaitObject *wait_object = GetCurrentProcess().GetWaitObjectPointer(); - - /* Convert the timeout from nanoseconds to ticks. */ - s64 timeout; - if (ns > 0) { - u64 ticks = KHardwareTimer::GetTick(); - ticks += ams::svc::Tick(TimeSpan::FromNanoSeconds(ns)); - ticks += 2; - - timeout = ticks; - } else { - timeout = ns; - } - - /* Synchronize to the desired time. */ - R_TRY(wait_object->Synchronize(timeout)); - } + R_TRY(SynchronizeCurrentProcessToFutureTime(ns)); /* Get the running thread info. */ R_TRY(debug->GetRunningThreadInfo(out_context, out_thread_id)); @@ -56,35 +88,25 @@ namespace ams::kern::svc { return ResultSuccess(); } + Result LegacyGetFutureThreadInfo(ams::svc::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags, int64_t ns) { + /* Only allow invoking the svc on development hardware. */ + R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNoThread()); + + /* Synchronize the current process to the desired time. */ + R_TRY(SynchronizeCurrentProcessToFutureTime(ns)); + + /* Get the thread info. */ + R_TRY(GetLastThreadInfoImpl(out_context, out_tls_address, out_flags)); + + return ResultSuccess(); + } + Result GetLastThreadInfo(ams::svc::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNoThread()); /* Get the thread info. */ - { - KScopedInterruptDisable di; - - /* Get the previous thread. */ - KThread *prev_thread = Kernel::GetScheduler().GetPreviousThread(); - R_UNLESS(prev_thread != nullptr, svc::ResultNoThread()); - - /* Verify the last thread was owned by the current process. */ - R_UNLESS(prev_thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultUnknownThread()); - - /* Clear the output flags. */ - *out_flags = 0; - - /* Get the thread's exception context. */ - GetExceptionContext(prev_thread)->GetSvcThreadContext(out_context); - - /* Get the tls address. */ - *out_tls_address = GetInteger(prev_thread->GetThreadLocalRegionAddress()); - - /* Set the syscall flag if appropriate. */ - if (prev_thread->IsCallingSvc()) { - *out_flags |= ams::svc::LastThreadInfoFlag_ThreadInSystemCall; - } - } + R_TRY(GetLastThreadInfoImpl(out_context, out_tls_address, out_flags)); return ResultSuccess(); } @@ -97,6 +119,10 @@ namespace ams::kern::svc { return GetDebugFutureThreadInfo(out_context, out_thread_id, debug_handle, ns); } + Result LegacyGetFutureThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags, int64_t ns) { + return LegacyGetFutureThreadInfo(out_context, reinterpret_cast(out_tls_address), out_flags, ns); + } + Result GetLastThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags) { static_assert(sizeof(*out_tls_address) == sizeof(uintptr_t)); return GetLastThreadInfo(out_context, reinterpret_cast(out_tls_address), out_flags); @@ -117,6 +143,21 @@ namespace ams::kern::svc { return ResultSuccess(); } + Result LegacyGetFutureThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags, int64_t ns) { + static_assert(sizeof(*out_tls_address) == sizeof(uintptr_t)); + + ams::svc::LastThreadContext context = {}; + R_TRY(LegacyGetFutureThreadInfo(std::addressof(context), reinterpret_cast(out_tls_address), out_flags, ns)); + + *out_context = { + .fp = static_cast(context.fp), + .sp = static_cast(context.sp), + .lr = static_cast(context.lr), + .pc = static_cast(context.pc), + }; + return ResultSuccess(); + } + Result GetLastThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags) { static_assert(sizeof(*out_tls_address) == sizeof(uintptr_t)); diff --git a/libraries/libvapours/include/vapours/svc/svc_definitions.hpp b/libraries/libvapours/include/vapours/svc/svc_definitions.hpp index 558051a49..51bb6faee 100644 --- a/libraries/libvapours/include/vapours/svc/svc_definitions.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_definitions.hpp @@ -151,6 +151,7 @@ HANDLER(0x7E, Result, SetResourceLimitLimitValue, INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which), INPUT(int64_t, limit_value)) \ HANDLER(0x7F, void, CallSecureMonitor, OUTPUT(::ams::svc::NAMESPACE::SecureMonitorArguments, args)) \ \ + HANDLER(0x2E, Result, LegacyGetFutureThreadInfo, OUTPUT(::ams::svc::NAMESPACE::LastThreadContext, out_context), OUTPUT(::ams::svc::Address, out_tls_address), OUTPUT(uint32_t, out_flags), INPUT(int64_t, ns)) \ HANDLER(0x55, Result, LegacyQueryIoMapping, OUTPUT(::ams::svc::Address, out_address), INPUT(::ams::svc::PhysicalAddress, physical_address), INPUT(::ams::svc::Size, size)) \ HANDLER(0x64, Result, LegacyContinueDebugEvent, INPUT(::ams::svc::Handle, debug_handle), INPUT(uint32_t, flags), INPUT(uint64_t, thread_id))