diff options
| author | 2014-12-04 14:45:47 -0500 | |
|---|---|---|
| committer | 2015-01-08 21:22:14 -0500 | |
| commit | 07044651ef2644451dc4f78045856ad078cb69fe (patch) | |
| tree | 50113ade759854c60c0e91864f27f2f680993e84 /src | |
| parent | Merge pull request #425 from Subv/coretiming (diff) | |
| download | yuzu-07044651ef2644451dc4f78045856ad078cb69fe.tar.gz yuzu-07044651ef2644451dc4f78045856ad078cb69fe.tar.xz yuzu-07044651ef2644451dc4f78045856ad078cb69fe.zip | |
SVC: Implemented the Timer service calls.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/function_wrappers.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 142 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.h | 47 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 36 |
8 files changed, 234 insertions, 5 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b67226d8d..8723a471f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -31,6 +31,7 @@ set(SRCS | |||
| 31 | hle/kernel/mutex.cpp | 31 | hle/kernel/mutex.cpp |
| 32 | hle/kernel/semaphore.cpp | 32 | hle/kernel/semaphore.cpp |
| 33 | hle/kernel/shared_memory.cpp | 33 | hle/kernel/shared_memory.cpp |
| 34 | hle/kernel/timer.cpp | ||
| 34 | hle/kernel/thread.cpp | 35 | hle/kernel/thread.cpp |
| 35 | hle/service/ac_u.cpp | 36 | hle/service/ac_u.cpp |
| 36 | hle/service/act_u.cpp | 37 | hle/service/act_u.cpp |
| @@ -123,6 +124,7 @@ set(HEADERS | |||
| 123 | hle/kernel/semaphore.h | 124 | hle/kernel/semaphore.h |
| 124 | hle/kernel/session.h | 125 | hle/kernel/session.h |
| 125 | hle/kernel/shared_memory.h | 126 | hle/kernel/shared_memory.h |
| 127 | hle/kernel/timer.h | ||
| 126 | hle/kernel/thread.h | 128 | hle/kernel/thread.h |
| 127 | hle/service/ac_u.h | 129 | hle/service/ac_u.h |
| 128 | hle/service/act_u.h | 130 | hle/service/act_u.h |
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 0f822f84b..8eb4f252b 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -135,6 +135,12 @@ template<s32 func(u32*, u32, u32, u32, u32)> void Wrap() { | |||
| 135 | FuncReturn(retval); | 135 | FuncReturn(retval); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | template<s32 func(u32, s64, s64)> void Wrap() { | ||
| 139 | s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2); | ||
| 140 | s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1); | ||
| 141 | FuncReturn(func(PARAM(0), param1, param2)); | ||
| 142 | } | ||
| 143 | |||
| 138 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 144 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 139 | // Function wrappers that return type u32 | 145 | // Function wrappers that return type u32 |
| 140 | 146 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e59ed1b57..084fd03ae 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/thread.h" | 11 | #include "core/hle/kernel/thread.h" |
| 12 | #include "core/hle/kernel/timer.h" | ||
| 12 | 13 | ||
| 13 | namespace Kernel { | 14 | namespace Kernel { |
| 14 | 15 | ||
| @@ -105,12 +106,13 @@ void HandleTable::Clear() { | |||
| 105 | /// Initialize the kernel | 106 | /// Initialize the kernel |
| 106 | void Init() { | 107 | void Init() { |
| 107 | Kernel::ThreadingInit(); | 108 | Kernel::ThreadingInit(); |
| 109 | Kernel::TimersInit(); | ||
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | /// Shutdown the kernel | 112 | /// Shutdown the kernel |
| 111 | void Shutdown() { | 113 | void Shutdown() { |
| 112 | Kernel::ThreadingShutdown(); | 114 | Kernel::ThreadingShutdown(); |
| 113 | 115 | Kernel::TimersShutdown(); | |
| 114 | g_handle_table.Clear(); // Free all kernel objects | 116 | g_handle_table.Clear(); // Free all kernel objects |
| 115 | } | 117 | } |
| 116 | 118 | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7f86fd07d..3e381d776 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -39,6 +39,7 @@ enum class HandleType : u32 { | |||
| 39 | Process = 8, | 39 | Process = 8, |
| 40 | AddressArbiter = 9, | 40 | AddressArbiter = 9, |
| 41 | Semaphore = 10, | 41 | Semaphore = 10, |
| 42 | Timer = 11 | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | enum { | 45 | enum { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0e1397cd9..81736a866 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -43,6 +43,7 @@ enum WaitType { | |||
| 43 | WAITTYPE_MUTEX, | 43 | WAITTYPE_MUTEX, |
| 44 | WAITTYPE_SYNCH, | 44 | WAITTYPE_SYNCH, |
| 45 | WAITTYPE_ARB, | 45 | WAITTYPE_ARB, |
| 46 | WAITTYPE_TIMER, | ||
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| 48 | namespace Kernel { | 49 | namespace Kernel { |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp new file mode 100644 index 000000000..7ac669e31 --- /dev/null +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <set> | ||
| 6 | |||
| 7 | #include "common/common.h" | ||
| 8 | |||
| 9 | #include "core/core_timing.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/timer.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class Timer : public Object { | ||
| 17 | public: | ||
| 18 | std::string GetTypeName() const override { return "Timer"; } | ||
| 19 | std::string GetName() const override { return name; } | ||
| 20 | |||
| 21 | static const HandleType HANDLE_TYPE = HandleType::Timer; | ||
| 22 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 23 | |||
| 24 | ResetType reset_type; ///< The ResetType of this timer | ||
| 25 | |||
| 26 | bool signaled; ///< Whether the timer has been signaled or not | ||
| 27 | std::set<Handle> waiting_threads; ///< Threads that are waiting for the timer | ||
| 28 | std::string name; ///< Name of timer (optional) | ||
| 29 | |||
| 30 | u64 initial_delay; ///< The delay until the timer fires for the first time | ||
| 31 | u64 interval_delay; ///< The delay until the timer fires after the first time | ||
| 32 | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | ||
| 34 | bool wait = !signaled; | ||
| 35 | if (wait) { | ||
| 36 | waiting_threads.insert(GetCurrentThreadHandle()); | ||
| 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, GetHandle()); | ||
| 38 | } | ||
| 39 | return MakeResult<bool>(wait); | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Creates a timer. | ||
| 45 | * @param handle Reference to handle for the newly created timer | ||
| 46 | * @param reset_type ResetType describing how to create timer | ||
| 47 | * @param name Optional name of timer | ||
| 48 | * @return Newly created Timer object | ||
| 49 | */ | ||
| 50 | Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 51 | Timer* timer = new Timer; | ||
| 52 | |||
| 53 | handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); | ||
| 54 | |||
| 55 | timer->reset_type = reset_type; | ||
| 56 | timer->signaled = false; | ||
| 57 | timer->name = name; | ||
| 58 | timer->initial_delay = 0; | ||
| 59 | timer->interval_delay = 0; | ||
| 60 | return timer; | ||
| 61 | } | ||
| 62 | |||
| 63 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { | ||
| 64 | CreateTimer(*handle, reset_type, name); | ||
| 65 | return RESULT_SUCCESS; | ||
| 66 | } | ||
| 67 | |||
| 68 | ResultCode ClearTimer(Handle handle) { | ||
| 69 | Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 70 | |||
| 71 | if (timer == nullptr) | ||
| 72 | return InvalidHandle(ErrorModule::Kernel); | ||
| 73 | |||
| 74 | timer->signaled = false; | ||
| 75 | return RESULT_SUCCESS; | ||
| 76 | } | ||
| 77 | |||
| 78 | /// The event type of the generic timer callback event | ||
| 79 | static int TimerCallbackEventType = -1; | ||
| 80 | |||
| 81 | /// The timer callback event, called when a timer is fired | ||
| 82 | static void TimerCallback(u64 timer_handle, int cycles_late) { | ||
| 83 | Timer* timer = Kernel::g_handle_table.Get<Timer>(timer_handle); | ||
| 84 | |||
| 85 | if (timer == nullptr) { | ||
| 86 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | LOG_TRACE(Kernel, "Timer %u fired", timer_handle); | ||
| 91 | |||
| 92 | timer->signaled = true; | ||
| 93 | |||
| 94 | // Resume all waiting threads | ||
| 95 | for (Handle thread : timer->waiting_threads) | ||
| 96 | ResumeThreadFromWait(thread); | ||
| 97 | |||
| 98 | timer->waiting_threads.clear(); | ||
| 99 | |||
| 100 | if (timer->reset_type == RESETTYPE_ONESHOT) | ||
| 101 | timer->signaled = false; | ||
| 102 | |||
| 103 | if (timer->interval_delay != 0) { | ||
| 104 | // Reschedule the timer with the interval delay | ||
| 105 | u64 interval_microseconds = timer->interval_delay / 1000; | ||
| 106 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, | ||
| 107 | TimerCallbackEventType, timer_handle); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { | ||
| 112 | Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 113 | |||
| 114 | if (timer == nullptr) | ||
| 115 | return InvalidHandle(ErrorModule::Kernel); | ||
| 116 | |||
| 117 | timer->initial_delay = initial; | ||
| 118 | timer->interval_delay = interval; | ||
| 119 | |||
| 120 | u64 initial_microseconds = initial / 1000; | ||
| 121 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); | ||
| 122 | return RESULT_SUCCESS; | ||
| 123 | } | ||
| 124 | |||
| 125 | ResultCode CancelTimer(Handle handle) { | ||
| 126 | Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 127 | |||
| 128 | if (timer == nullptr) | ||
| 129 | return InvalidHandle(ErrorModule::Kernel); | ||
| 130 | |||
| 131 | CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); | ||
| 132 | return RESULT_SUCCESS; | ||
| 133 | } | ||
| 134 | |||
| 135 | void TimersInit() { | ||
| 136 | TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | ||
| 137 | } | ||
| 138 | |||
| 139 | void TimersShutdown() { | ||
| 140 | } | ||
| 141 | |||
| 142 | } // namespace | ||
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h new file mode 100644 index 000000000..f8aa66b60 --- /dev/null +++ b/src/core/hle/kernel/timer.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/hle/kernel/kernel.h" | ||
| 10 | #include "core/hle/svc.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Cancels a timer | ||
| 16 | * @param handle Handle of the timer to cancel | ||
| 17 | */ | ||
| 18 | ResultCode CancelTimer(Handle handle); | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Starts a timer with the specified initial delay and interval | ||
| 22 | * @param handle Handle of the timer to start | ||
| 23 | * @param initial Delay until the timer is first fired | ||
| 24 | * @param interval Delay until the timer is fired after the first time | ||
| 25 | */ | ||
| 26 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Clears a timer | ||
| 30 | * @param handle Handle of the timer to clear | ||
| 31 | */ | ||
| 32 | ResultCode ClearTimer(Handle handle); | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Creates a timer | ||
| 36 | * @param Handle to newly created Timer object | ||
| 37 | * @param reset_type ResetType describing how to create the timer | ||
| 38 | * @param name Optional name of timer | ||
| 39 | * @return ResultCode of the error | ||
| 40 | */ | ||
| 41 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); | ||
| 42 | |||
| 43 | /// Initializes the required variables for timers | ||
| 44 | void TimersInit(); | ||
| 45 | /// Tears down the timer variables | ||
| 46 | void TimersShutdown(); | ||
| 47 | } // namespace | ||
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c25409a9f..0cf3de75c 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/hle/kernel/semaphore.h" | 15 | #include "core/hle/kernel/semaphore.h" |
| 16 | #include "core/hle/kernel/shared_memory.h" | 16 | #include "core/hle/kernel/shared_memory.h" |
| 17 | #include "core/hle/kernel/thread.h" | 17 | #include "core/hle/kernel/thread.h" |
| 18 | #include "core/hle/kernel/timer.h" | ||
| 18 | 19 | ||
| 19 | #include "core/hle/function_wrappers.h" | 20 | #include "core/hle/function_wrappers.h" |
| 20 | #include "core/hle/result.h" | 21 | #include "core/hle/result.h" |
| @@ -139,6 +140,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 139 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 140 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 140 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, | 141 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, |
| 141 | s64 nano_seconds) { | 142 | s64 nano_seconds) { |
| 143 | |||
| 142 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this | 144 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this |
| 143 | bool unlock_all = true; | 145 | bool unlock_all = true; |
| 144 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | 146 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated |
| @@ -338,6 +340,32 @@ static Result ClearEvent(Handle evt) { | |||
| 338 | return Kernel::ClearEvent(evt).raw; | 340 | return Kernel::ClearEvent(evt).raw; |
| 339 | } | 341 | } |
| 340 | 342 | ||
| 343 | /// Creates a timer | ||
| 344 | static Result CreateTimer(Handle* handle, u32 reset_type) { | ||
| 345 | ResultCode res = Kernel::CreateTimer(handle, static_cast<ResetType>(reset_type)); | ||
| 346 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | ||
| 347 | reset_type, *handle); | ||
| 348 | return res.raw; | ||
| 349 | } | ||
| 350 | |||
| 351 | /// Clears a timer | ||
| 352 | static Result ClearTimer(Handle handle) { | ||
| 353 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | ||
| 354 | return Kernel::ClearTimer(handle).raw; | ||
| 355 | } | ||
| 356 | |||
| 357 | /// Starts a timer | ||
| 358 | static Result SetTimer(Handle handle, s64 initial, s64 interval) { | ||
| 359 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | ||
| 360 | return Kernel::SetTimer(handle, initial, interval).raw; | ||
| 361 | } | ||
| 362 | |||
| 363 | /// Cancels a timer | ||
| 364 | static Result CancelTimer(Handle handle) { | ||
| 365 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | ||
| 366 | return Kernel::CancelTimer(handle).raw; | ||
| 367 | } | ||
| 368 | |||
| 341 | /// Sleep the current thread | 369 | /// Sleep the current thread |
| 342 | static void SleepThread(s64 nanoseconds) { | 370 | static void SleepThread(s64 nanoseconds) { |
| 343 | LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); | 371 | LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); |
| @@ -391,10 +419,10 @@ const HLE::FunctionDef SVC_Table[] = { | |||
| 391 | {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, | 419 | {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, |
| 392 | {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, | 420 | {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, |
| 393 | {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, | 421 | {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, |
| 394 | {0x1A, nullptr, "CreateTimer"}, | 422 | {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"}, |
| 395 | {0x1B, nullptr, "SetTimer"}, | 423 | {0x1B, HLE::Wrap<SetTimer>, "SetTimer"}, |
| 396 | {0x1C, nullptr, "CancelTimer"}, | 424 | {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"}, |
| 397 | {0x1D, nullptr, "ClearTimer"}, | 425 | {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"}, |
| 398 | {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"}, | 426 | {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"}, |
| 399 | {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, | 427 | {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, |
| 400 | {0x20, nullptr, "UnmapMemoryBlock"}, | 428 | {0x20, nullptr, "UnmapMemoryBlock"}, |