diff options
| author | 2018-10-28 04:38:48 -0400 | |
|---|---|---|
| committer | 2018-10-28 04:38:48 -0400 | |
| commit | 2239d4711288ffb61c9ac25ce19e3b6b1e15107f (patch) | |
| tree | 90cd62acff8b352bfbdb796e8e947416cb8496f5 | |
| parent | Merge pull request #1581 from FreddyFunk/macosx-target-version (diff) | |
| parent | svc: Localize the GetInfo enum class to the function itself (diff) | |
| download | yuzu-2239d4711288ffb61c9ac25ce19e3b6b1e15107f.tar.gz yuzu-2239d4711288ffb61c9ac25ce19e3b6b1e15107f.tar.xz yuzu-2239d4711288ffb61c9ac25ce19e3b6b1e15107f.zip | |
Merge pull request #1593 from lioncash/svc
svc: Implement svcGetInfo command 0xF0000002
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/process.h | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.cpp | 28 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.h | 19 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 61 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.h | 31 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 11 |
6 files changed, 128 insertions, 35 deletions
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: | |||
| 202 | return is_64bit_process; | 202 | return is_64bit_process; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | /// Gets the total running time of the process instance in ticks. | ||
| 206 | u64 GetCPUTimeTicks() const { | ||
| 207 | return total_process_running_time_ticks; | ||
| 208 | } | ||
| 209 | |||
| 210 | /// Updates the total running time, adding the given ticks to it. | ||
| 211 | void UpdateCPUTimeTicks(u64 ticks) { | ||
| 212 | total_process_running_time_ticks += ticks; | ||
| 213 | } | ||
| 214 | |||
| 205 | /** | 215 | /** |
| 206 | * Loads process-specifics configuration info with metadata provided | 216 | * Loads process-specifics configuration info with metadata provided |
| 207 | * by an executable. | 217 | * by an executable. |
| @@ -305,6 +315,9 @@ private: | |||
| 305 | /// specified by metadata provided to the process during loading. | 315 | /// specified by metadata provided to the process during loading. |
| 306 | bool is_64bit_process = true; | 316 | bool is_64bit_process = true; |
| 307 | 317 | ||
| 318 | /// Total running time for the process in ticks. | ||
| 319 | u64 total_process_running_time_ticks = 0; | ||
| 320 | |||
| 308 | /// Per-process handle table for storing created object handles in. | 321 | /// Per-process handle table for storing created object handles in. |
| 309 | HandleTable handle_table; | 322 | HandleTable handle_table; |
| 310 | 323 | ||
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 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/arm/arm_interface.h" | 10 | #include "core/arm/arm_interface.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/core_timing.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/scheduler.h" | 15 | #include "core/hle/kernel/scheduler.h" |
| @@ -34,6 +35,10 @@ Thread* Scheduler::GetCurrentThread() const { | |||
| 34 | return current_thread.get(); | 35 | return current_thread.get(); |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | u64 Scheduler::GetLastContextSwitchTicks() const { | ||
| 39 | return last_context_switch_time; | ||
| 40 | } | ||
| 41 | |||
| 37 | Thread* Scheduler::PopNextReadyThread() { | 42 | Thread* Scheduler::PopNextReadyThread() { |
| 38 | Thread* next = nullptr; | 43 | Thread* next = nullptr; |
| 39 | Thread* thread = GetCurrentThread(); | 44 | Thread* thread = GetCurrentThread(); |
| @@ -54,7 +59,10 @@ Thread* Scheduler::PopNextReadyThread() { | |||
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | void Scheduler::SwitchContext(Thread* new_thread) { | 61 | void Scheduler::SwitchContext(Thread* new_thread) { |
| 57 | Thread* previous_thread = GetCurrentThread(); | 62 | Thread* const previous_thread = GetCurrentThread(); |
| 63 | Process* const previous_process = Core::CurrentProcess(); | ||
| 64 | |||
| 65 | UpdateLastContextSwitchTime(previous_thread, previous_process); | ||
| 58 | 66 | ||
| 59 | // Save context for previous thread | 67 | // Save context for previous thread |
| 60 | if (previous_thread) { | 68 | if (previous_thread) { |
| @@ -78,8 +86,6 @@ void Scheduler::SwitchContext(Thread* new_thread) { | |||
| 78 | // Cancel any outstanding wakeup events for this thread | 86 | // Cancel any outstanding wakeup events for this thread |
| 79 | new_thread->CancelWakeupTimer(); | 87 | new_thread->CancelWakeupTimer(); |
| 80 | 88 | ||
| 81 | auto* const previous_process = Core::CurrentProcess(); | ||
| 82 | |||
| 83 | current_thread = new_thread; | 89 | current_thread = new_thread; |
| 84 | 90 | ||
| 85 | ready_queue.remove(new_thread->GetPriority(), new_thread); | 91 | ready_queue.remove(new_thread->GetPriority(), new_thread); |
| @@ -102,6 +108,22 @@ void Scheduler::SwitchContext(Thread* new_thread) { | |||
| 102 | } | 108 | } |
| 103 | } | 109 | } |
| 104 | 110 | ||
| 111 | void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { | ||
| 112 | const u64 prev_switch_ticks = last_context_switch_time; | ||
| 113 | const u64 most_recent_switch_ticks = CoreTiming::GetTicks(); | ||
| 114 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; | ||
| 115 | |||
| 116 | if (thread != nullptr) { | ||
| 117 | thread->UpdateCPUTimeTicks(update_ticks); | ||
| 118 | } | ||
| 119 | |||
| 120 | if (process != nullptr) { | ||
| 121 | process->UpdateCPUTimeTicks(update_ticks); | ||
| 122 | } | ||
| 123 | |||
| 124 | last_context_switch_time = most_recent_switch_ticks; | ||
| 125 | } | ||
| 126 | |||
| 105 | void Scheduler::Reschedule() { | 127 | void Scheduler::Reschedule() { |
| 106 | std::lock_guard<std::mutex> lock(scheduler_mutex); | 128 | std::lock_guard<std::mutex> lock(scheduler_mutex); |
| 107 | 129 | ||
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; | |||
| 17 | 17 | ||
| 18 | namespace Kernel { | 18 | namespace Kernel { |
| 19 | 19 | ||
| 20 | class Process; | ||
| 21 | |||
| 20 | class Scheduler final { | 22 | class Scheduler final { |
| 21 | public: | 23 | public: |
| 22 | explicit Scheduler(Core::ARM_Interface& cpu_core); | 24 | explicit Scheduler(Core::ARM_Interface& cpu_core); |
| @@ -31,6 +33,9 @@ public: | |||
| 31 | /// Gets the current running thread | 33 | /// Gets the current running thread |
| 32 | Thread* GetCurrentThread() const; | 34 | Thread* GetCurrentThread() const; |
| 33 | 35 | ||
| 36 | /// Gets the timestamp for the last context switch in ticks. | ||
| 37 | u64 GetLastContextSwitchTicks() const; | ||
| 38 | |||
| 34 | /// Adds a new thread to the scheduler | 39 | /// Adds a new thread to the scheduler |
| 35 | void AddThread(SharedPtr<Thread> thread, u32 priority); | 40 | void AddThread(SharedPtr<Thread> thread, u32 priority); |
| 36 | 41 | ||
| @@ -64,6 +69,19 @@ private: | |||
| 64 | */ | 69 | */ |
| 65 | void SwitchContext(Thread* new_thread); | 70 | void SwitchContext(Thread* new_thread); |
| 66 | 71 | ||
| 72 | /** | ||
| 73 | * Called on every context switch to update the internal timestamp | ||
| 74 | * This also updates the running time ticks for the given thread and | ||
| 75 | * process using the following difference: | ||
| 76 | * | ||
| 77 | * ticks += most_recent_ticks - last_context_switch_ticks | ||
| 78 | * | ||
| 79 | * The internal tick timestamp for the scheduler is simply the | ||
| 80 | * most recent tick count retrieved. No special arithmetic is | ||
| 81 | * applied to it. | ||
| 82 | */ | ||
| 83 | void UpdateLastContextSwitchTime(Thread* thread, Process* process); | ||
| 84 | |||
| 67 | /// Lists all thread ids that aren't deleted/etc. | 85 | /// Lists all thread ids that aren't deleted/etc. |
| 68 | std::vector<SharedPtr<Thread>> thread_list; | 86 | std::vector<SharedPtr<Thread>> thread_list; |
| 69 | 87 | ||
| @@ -73,6 +91,7 @@ private: | |||
| 73 | SharedPtr<Thread> current_thread = nullptr; | 91 | SharedPtr<Thread> current_thread = nullptr; |
| 74 | 92 | ||
| 75 | Core::ARM_Interface& cpu_core; | 93 | Core::ARM_Interface& cpu_core; |
| 94 | u64 last_context_switch_time = 0; | ||
| 76 | 95 | ||
| 77 | static std::mutex scheduler_mutex; | 96 | static std::mutex scheduler_mutex; |
| 78 | }; | 97 | }; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a5302d924..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) | |||
| 467 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, | 467 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, |
| 468 | info_sub_id, handle); | 468 | info_sub_id, handle); |
| 469 | 469 | ||
| 470 | enum class GetInfoType : u64 { | ||
| 471 | // 1.0.0+ | ||
| 472 | AllowedCpuIdBitmask = 0, | ||
| 473 | AllowedThreadPrioBitmask = 1, | ||
| 474 | MapRegionBaseAddr = 2, | ||
| 475 | MapRegionSize = 3, | ||
| 476 | HeapRegionBaseAddr = 4, | ||
| 477 | HeapRegionSize = 5, | ||
| 478 | TotalMemoryUsage = 6, | ||
| 479 | TotalHeapUsage = 7, | ||
| 480 | IsCurrentProcessBeingDebugged = 8, | ||
| 481 | ResourceHandleLimit = 9, | ||
| 482 | IdleTickCount = 10, | ||
| 483 | RandomEntropy = 11, | ||
| 484 | PerformanceCounter = 0xF0000002, | ||
| 485 | // 2.0.0+ | ||
| 486 | ASLRRegionBaseAddr = 12, | ||
| 487 | ASLRRegionSize = 13, | ||
| 488 | NewMapRegionBaseAddr = 14, | ||
| 489 | NewMapRegionSize = 15, | ||
| 490 | // 3.0.0+ | ||
| 491 | IsVirtualAddressMemoryEnabled = 16, | ||
| 492 | PersonalMmHeapUsage = 17, | ||
| 493 | TitleId = 18, | ||
| 494 | // 4.0.0+ | ||
| 495 | PrivilegedProcessId = 19, | ||
| 496 | // 5.0.0+ | ||
| 497 | UserExceptionContextAddr = 20, | ||
| 498 | ThreadTickCount = 0xF0000002, | ||
| 499 | }; | ||
| 500 | |||
| 470 | const auto* current_process = Core::CurrentProcess(); | 501 | const auto* current_process = Core::CurrentProcess(); |
| 471 | const auto& vm_manager = current_process->VMManager(); | 502 | const auto& vm_manager = current_process->VMManager(); |
| 472 | 503 | ||
| @@ -529,6 +560,36 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 529 | "(STUBBED) Attempted to query user exception context address, returned 0"); | 560 | "(STUBBED) Attempted to query user exception context address, returned 0"); |
| 530 | *result = 0; | 561 | *result = 0; |
| 531 | break; | 562 | break; |
| 563 | case GetInfoType::ThreadTickCount: { | ||
| 564 | constexpr u64 num_cpus = 4; | ||
| 565 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { | ||
| 566 | return ERR_INVALID_COMBINATION_KERNEL; | ||
| 567 | } | ||
| 568 | |||
| 569 | const auto thread = | ||
| 570 | current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); | ||
| 571 | if (!thread) { | ||
| 572 | return ERR_INVALID_HANDLE; | ||
| 573 | } | ||
| 574 | |||
| 575 | auto& system = Core::System::GetInstance(); | ||
| 576 | const auto& scheduler = system.CurrentScheduler(); | ||
| 577 | const auto* const current_thread = scheduler.GetCurrentThread(); | ||
| 578 | const bool same_thread = current_thread == thread; | ||
| 579 | |||
| 580 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); | ||
| 581 | u64 out_ticks = 0; | ||
| 582 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { | ||
| 583 | const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); | ||
| 584 | |||
| 585 | out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks); | ||
| 586 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { | ||
| 587 | out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks; | ||
| 588 | } | ||
| 589 | |||
| 590 | *result = out_ticks; | ||
| 591 | break; | ||
| 592 | } | ||
| 532 | default: | 593 | default: |
| 533 | UNIMPLEMENTED(); | 594 | UNIMPLEMENTED(); |
| 534 | } | 595 | } |
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 554a5e328..b06aac4ec 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h | |||
| @@ -24,37 +24,6 @@ struct PageInfo { | |||
| 24 | u64 flags; | 24 | u64 flags; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | /// Values accepted by svcGetInfo | ||
| 28 | enum class GetInfoType : u64 { | ||
| 29 | // 1.0.0+ | ||
| 30 | AllowedCpuIdBitmask = 0, | ||
| 31 | AllowedThreadPrioBitmask = 1, | ||
| 32 | MapRegionBaseAddr = 2, | ||
| 33 | MapRegionSize = 3, | ||
| 34 | HeapRegionBaseAddr = 4, | ||
| 35 | HeapRegionSize = 5, | ||
| 36 | TotalMemoryUsage = 6, | ||
| 37 | TotalHeapUsage = 7, | ||
| 38 | IsCurrentProcessBeingDebugged = 8, | ||
| 39 | ResourceHandleLimit = 9, | ||
| 40 | IdleTickCount = 10, | ||
| 41 | RandomEntropy = 11, | ||
| 42 | PerformanceCounter = 0xF0000002, | ||
| 43 | // 2.0.0+ | ||
| 44 | ASLRRegionBaseAddr = 12, | ||
| 45 | ASLRRegionSize = 13, | ||
| 46 | NewMapRegionBaseAddr = 14, | ||
| 47 | NewMapRegionSize = 15, | ||
| 48 | // 3.0.0+ | ||
| 49 | IsVirtualAddressMemoryEnabled = 16, | ||
| 50 | PersonalMmHeapUsage = 17, | ||
| 51 | TitleId = 18, | ||
| 52 | // 4.0.0+ | ||
| 53 | PrivilegedProcessId = 19, | ||
| 54 | // 5.0.0+ | ||
| 55 | UserExceptionContextAddr = 20, | ||
| 56 | }; | ||
| 57 | |||
| 58 | void CallSVC(u32 immediate); | 27 | void CallSVC(u32 immediate); |
| 59 | 28 | ||
| 60 | } // namespace Kernel | 29 | } // namespace Kernel |
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: | |||
| 258 | return last_running_ticks; | 258 | return last_running_ticks; |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | u64 GetTotalCPUTimeTicks() const { | ||
| 262 | return total_cpu_time_ticks; | ||
| 263 | } | ||
| 264 | |||
| 265 | void UpdateCPUTimeTicks(u64 ticks) { | ||
| 266 | total_cpu_time_ticks += ticks; | ||
| 267 | } | ||
| 268 | |||
| 261 | s32 GetProcessorID() const { | 269 | s32 GetProcessorID() const { |
| 262 | return processor_id; | 270 | return processor_id; |
| 263 | } | 271 | } |
| @@ -378,7 +386,8 @@ private: | |||
| 378 | u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application | 386 | u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application |
| 379 | u32 current_priority = 0; ///< Current thread priority, can be temporarily changed | 387 | u32 current_priority = 0; ///< Current thread priority, can be temporarily changed |
| 380 | 388 | ||
| 381 | u64 last_running_ticks = 0; ///< CPU tick when thread was last running | 389 | u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. |
| 390 | u64 last_running_ticks = 0; ///< CPU tick when thread was last running | ||
| 382 | 391 | ||
| 383 | s32 processor_id = 0; | 392 | s32 processor_id = 0; |
| 384 | 393 | ||