diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp index f555f7837..123a7fb49 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp @@ -82,6 +82,14 @@ namespace ams::kern { this->ScheduleOnInterrupt(); } } + + ALWAYS_INLINE KThread *GetIdleThread() const { + return this->idle_thread; + } + + ALWAYS_INLINE s64 GetLastContextSwitchTime() const { + return this->last_context_switch_time; + } private: /* Static private API. */ static ALWAYS_INLINE bool IsSchedulerUpdateNeeded() { return s_scheduler_update_needed; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 01e9c7934..87f7f9b0d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -427,8 +427,18 @@ namespace ams::kern { constexpr void SetDebugAttached() { this->debug_attached = true; } constexpr bool IsAttachedToDebugger() const { return this->debug_attached; } - void AddCpuTime(s64 amount) { + void AddCpuTime(s32 core_id, s64 amount) { this->cpu_time += amount; + /* TODO: Debug kernels track per-core tick counts. Should we? */ + } + + s64 GetCpuTime() const { return this->cpu_time; } + + s64 GetCpuTime(s32 core_id) const { + MESOSPHERE_ABORT_UNLESS(0 <= core_id && core_id < static_cast(cpu::NumCores)); + + /* TODO: Debug kernels track per-core tick counts. Should we? */ + return 0; } constexpr u32 GetSuspendFlags() const { return this->suspend_allowed_flags & this->suspend_request_flags; } diff --git a/libraries/libmesosphere/source/kern_k_scheduler.cpp b/libraries/libmesosphere/source/kern_k_scheduler.cpp index 46bfc8957..392a385ca 100644 --- a/libraries/libmesosphere/source/kern_k_scheduler.cpp +++ b/libraries/libmesosphere/source/kern_k_scheduler.cpp @@ -232,7 +232,7 @@ namespace ams::kern { const s64 prev_tick = this->last_context_switch_time; const s64 cur_tick = KHardwareTimer::GetTick(); const s64 tick_diff = cur_tick - prev_tick; - cur_thread->AddCpuTime(tick_diff); + cur_thread->AddCpuTime(this->core_id, tick_diff); if (cur_process != nullptr) { cur_process->AddCpuTime(tick_diff); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp index e8a3312b1..1a3c58798 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp @@ -153,6 +153,19 @@ namespace ams::kern::svc { } } break; + case ams::svc::InfoType_IdleTickCount: + { + /* Verify the input handle is invalid. */ + R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); + + /* Verify the requested core is valid. */ + const bool core_valid = (info_subtype == static_cast(-1ul)) || (info_subtype == static_cast(GetCurrentCoreId())); + R_UNLESS(core_valid, svc::ResultInvalidCombination()); + + /* Get the idle tick count. */ + *out = Kernel::GetScheduler().GetIdleThread()->GetCpuTime(); + } + break; case ams::svc::InfoType_RandomEntropy: { /* Verify the input handle is invalid. */ @@ -165,11 +178,42 @@ namespace ams::kern::svc { *out = GetCurrentProcess().GetRandomEntropy(info_subtype); } break; + case ams::svc::InfoType_ThreadTickCount: + { + /* Verify the requested core is valid. */ + const bool core_valid = (info_subtype == static_cast(-1ul)) || (info_subtype < cpu::NumCores); + R_UNLESS(core_valid, svc::ResultInvalidCombination()); + + /* Get the thread from its handle. */ + KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject(handle); + R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the tick count. */ + s64 tick_count; + if (info_subtype == static_cast(-1ul)) { + tick_count = thread->GetCpuTime(); + if (GetCurrentThreadPointer() == thread.GetPointerUnsafe()) { + const s64 cur_tick = KHardwareTimer::GetTick(); + const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime(); + tick_count += (cur_tick - prev_switch); + } + } else { + tick_count = thread->GetCpuTime(static_cast(info_subtype)); + if (GetCurrentThreadPointer() == thread.GetPointerUnsafe() && static_cast(info_subtype) == GetCurrentCoreId()) { + const s64 cur_tick = KHardwareTimer::GetTick(); + const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime(); + tick_count += (cur_tick - prev_switch); + } + } + + /* Set the output. */ + *out = tick_count; + } + break; default: { - /* For debug, until all infos are implemented. */ + /* For debug, log the invalid info call. */ MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast(info_type), static_cast(handle), info_subtype); - MESOSPHERE_UNIMPLEMENTED(); } return svc::ResultInvalidEnumValue(); }