From 6594853eb112f265fe2354723160c0d4e1cb761a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Oct 2018 18:42:50 -0400 Subject: svc: Implement svcGetInfo command 0xF0000002 This retrieves: if (curr_thread == handle_thread) { result = total_thread_ticks + (hardware_tick_count - last_context_switch_ticks); } else if (curr_thread == handle_thread && sub_id == current_core_index) { result = hardware_tick_count - last_context_switch_ticks; } --- src/core/hle/kernel/process.h | 13 +++++++++++++ src/core/hle/kernel/scheduler.cpp | 28 +++++++++++++++++++++++++--- src/core/hle/kernel/scheduler.h | 19 +++++++++++++++++++ src/core/hle/kernel/svc.cpp | 30 ++++++++++++++++++++++++++++++ src/core/hle/kernel/svc.h | 1 + src/core/hle/kernel/thread.h | 11 ++++++++++- 6 files changed, 98 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 148478488..8d2616c79 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -202,6 +202,16 @@ public: return is_64bit_process; } + /// Gets the total running time of the process instance in ticks. + u64 GetCPUTimeTicks() const { + return total_process_running_time_ticks; + } + + /// Updates the total running time, adding the given ticks to it. + void UpdateCPUTimeTicks(u64 ticks) { + total_process_running_time_ticks += ticks; + } + /** * Loads process-specifics configuration info with metadata provided * by an executable. @@ -305,6 +315,9 @@ private: /// specified by metadata provided to the process during loading. bool is_64bit_process = true; + /// Total running time for the process in ticks. + u64 total_process_running_time_ticks = 0; + /// Per-process handle table for storing created object handles in. HandleTable handle_table; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 1342c597e..5a5f4cef1 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" @@ -34,6 +35,10 @@ Thread* Scheduler::GetCurrentThread() const { return current_thread.get(); } +u64 Scheduler::GetLastContextSwitchTicks() const { + return last_context_switch_time; +} + Thread* Scheduler::PopNextReadyThread() { Thread* next = nullptr; Thread* thread = GetCurrentThread(); @@ -54,7 +59,10 @@ Thread* Scheduler::PopNextReadyThread() { } void Scheduler::SwitchContext(Thread* new_thread) { - Thread* previous_thread = GetCurrentThread(); + Thread* const previous_thread = GetCurrentThread(); + Process* const previous_process = Core::CurrentProcess(); + + UpdateLastContextSwitchTime(previous_thread, previous_process); // Save context for previous thread if (previous_thread) { @@ -78,8 +86,6 @@ void Scheduler::SwitchContext(Thread* new_thread) { // Cancel any outstanding wakeup events for this thread new_thread->CancelWakeupTimer(); - auto* const previous_process = Core::CurrentProcess(); - current_thread = new_thread; ready_queue.remove(new_thread->GetPriority(), new_thread); @@ -102,6 +108,22 @@ void Scheduler::SwitchContext(Thread* new_thread) { } } +void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { + const u64 prev_switch_ticks = last_context_switch_time; + const u64 most_recent_switch_ticks = CoreTiming::GetTicks(); + const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; + + if (thread != nullptr) { + thread->UpdateCPUTimeTicks(update_ticks); + } + + if (process != nullptr) { + process->UpdateCPUTimeTicks(update_ticks); + } + + last_context_switch_time = most_recent_switch_ticks; +} + void Scheduler::Reschedule() { std::lock_guard lock(scheduler_mutex); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 2c94641ec..c63032b7d 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -17,6 +17,8 @@ class ARM_Interface; namespace Kernel { +class Process; + class Scheduler final { public: explicit Scheduler(Core::ARM_Interface& cpu_core); @@ -31,6 +33,9 @@ public: /// Gets the current running thread Thread* GetCurrentThread() const; + /// Gets the timestamp for the last context switch in ticks. + u64 GetLastContextSwitchTicks() const; + /// Adds a new thread to the scheduler void AddThread(SharedPtr thread, u32 priority); @@ -64,6 +69,19 @@ private: */ void SwitchContext(Thread* new_thread); + /** + * Called on every context switch to update the internal timestamp + * This also updates the running time ticks for the given thread and + * process using the following difference: + * + * ticks += most_recent_ticks - last_context_switch_ticks + * + * The internal tick timestamp for the scheduler is simply the + * most recent tick count retrieved. No special arithmetic is + * applied to it. + */ + void UpdateLastContextSwitchTime(Thread* thread, Process* process); + /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; @@ -73,6 +91,7 @@ private: SharedPtr current_thread = nullptr; Core::ARM_Interface& cpu_core; + u64 last_context_switch_time = 0; static std::mutex scheduler_mutex; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a5302d924..110f042d7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -529,6 +529,36 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) "(STUBBED) Attempted to query user exception context address, returned 0"); *result = 0; break; + case GetInfoType::ThreadTickCount: { + constexpr u64 num_cpus = 4; + if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { + return ERR_INVALID_COMBINATION_KERNEL; + } + + const auto thread = + current_process->GetHandleTable().Get(static_cast(handle)); + if (!thread) { + return ERR_INVALID_HANDLE; + } + + auto& system = Core::System::GetInstance(); + const auto& scheduler = system.CurrentScheduler(); + const auto* const current_thread = scheduler.GetCurrentThread(); + const bool same_thread = current_thread == thread; + + const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); + u64 out_ticks = 0; + if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { + const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); + + out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks); + } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { + out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks; + } + + *result = out_ticks; + break; + } default: UNIMPLEMENTED(); } diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 554a5e328..948fd30e4 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -53,6 +53,7 @@ enum class GetInfoType : u64 { PrivilegedProcessId = 19, // 5.0.0+ UserExceptionContextAddr = 20, + ThreadTickCount = 0xF0000002, }; void CallSVC(u32 immediate); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f4d7bd235..4a6e11239 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -258,6 +258,14 @@ public: return last_running_ticks; } + u64 GetTotalCPUTimeTicks() const { + return total_cpu_time_ticks; + } + + void UpdateCPUTimeTicks(u64 ticks) { + total_cpu_time_ticks += ticks; + } + s32 GetProcessorID() const { return processor_id; } @@ -378,7 +386,8 @@ private: u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application u32 current_priority = 0; ///< Current thread priority, can be temporarily changed - u64 last_running_ticks = 0; ///< CPU tick when thread was last running + u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. + u64 last_running_ticks = 0; ///< CPU tick when thread was last running s32 processor_id = 0; -- cgit v1.2.3 From 7de8e3634323bbfcd4242581b2e45493a126710a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 26 Oct 2018 00:37:14 -0400 Subject: svc: Localize the GetInfo enum class to the function itself Nothing from this enum is intended to be used outside of this function. --- src/core/hle/kernel/svc.cpp | 31 +++++++++++++++++++++++++++++++ src/core/hle/kernel/svc.h | 32 -------------------------------- 2 files changed, 31 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 110f042d7..4e490e2b5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -467,6 +467,37 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); + enum class GetInfoType : u64 { + // 1.0.0+ + AllowedCpuIdBitmask = 0, + AllowedThreadPrioBitmask = 1, + MapRegionBaseAddr = 2, + MapRegionSize = 3, + HeapRegionBaseAddr = 4, + HeapRegionSize = 5, + TotalMemoryUsage = 6, + TotalHeapUsage = 7, + IsCurrentProcessBeingDebugged = 8, + ResourceHandleLimit = 9, + IdleTickCount = 10, + RandomEntropy = 11, + PerformanceCounter = 0xF0000002, + // 2.0.0+ + ASLRRegionBaseAddr = 12, + ASLRRegionSize = 13, + NewMapRegionBaseAddr = 14, + NewMapRegionSize = 15, + // 3.0.0+ + IsVirtualAddressMemoryEnabled = 16, + PersonalMmHeapUsage = 17, + TitleId = 18, + // 4.0.0+ + PrivilegedProcessId = 19, + // 5.0.0+ + UserExceptionContextAddr = 20, + ThreadTickCount = 0xF0000002, + }; + const auto* current_process = Core::CurrentProcess(); const auto& vm_manager = current_process->VMManager(); diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 948fd30e4..b06aac4ec 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -24,38 +24,6 @@ struct PageInfo { u64 flags; }; -/// Values accepted by svcGetInfo -enum class GetInfoType : u64 { - // 1.0.0+ - AllowedCpuIdBitmask = 0, - AllowedThreadPrioBitmask = 1, - MapRegionBaseAddr = 2, - MapRegionSize = 3, - HeapRegionBaseAddr = 4, - HeapRegionSize = 5, - TotalMemoryUsage = 6, - TotalHeapUsage = 7, - IsCurrentProcessBeingDebugged = 8, - ResourceHandleLimit = 9, - IdleTickCount = 10, - RandomEntropy = 11, - PerformanceCounter = 0xF0000002, - // 2.0.0+ - ASLRRegionBaseAddr = 12, - ASLRRegionSize = 13, - NewMapRegionBaseAddr = 14, - NewMapRegionSize = 15, - // 3.0.0+ - IsVirtualAddressMemoryEnabled = 16, - PersonalMmHeapUsage = 17, - TitleId = 18, - // 4.0.0+ - PrivilegedProcessId = 19, - // 5.0.0+ - UserExceptionContextAddr = 20, - ThreadTickCount = 0xF0000002, -}; - void CallSVC(u32 immediate); } // namespace Kernel -- cgit v1.2.3