Merge pull request #1593 from lioncash/svc
svc: Implement svcGetInfo command 0xF0000002
This commit is contained in:
		| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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<std::mutex> lock(scheduler_mutex); | ||||
|  | ||||
|   | ||||
| @@ -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> 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<SharedPtr<Thread>> thread_list; | ||||
|  | ||||
| @@ -73,6 +91,7 @@ private: | ||||
|     SharedPtr<Thread> current_thread = nullptr; | ||||
|  | ||||
|     Core::ARM_Interface& cpu_core; | ||||
|     u64 last_context_switch_time = 0; | ||||
|  | ||||
|     static std::mutex scheduler_mutex; | ||||
| }; | ||||
|   | ||||
| @@ -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(); | ||||
|  | ||||
| @@ -529,6 +560,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<Thread>(static_cast<Handle>(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(); | ||||
|     } | ||||
|   | ||||
| @@ -24,37 +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, | ||||
| }; | ||||
|  | ||||
| void CallSVC(u32 immediate); | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei