#include "kernel.hpp" #include "cpu.hpp" Handle Kernel::makeTimer(ResetType type) { Handle ret = makeObject(KernelObjectType::Timer); objects[ret].data = new Timer(type); if (type == ResetType::Pulse) { Helpers::panic("Created pulse timer"); } // timerHandles.push_back(ret); return ret; } void Kernel::updateTimer(Handle handle, Timer* timer) { if (timer->running) { const u64 currentTicks = cpu.getTicks(); u64 elapsedTicks = currentTicks - timer->startTick; constexpr double ticksPerSec = double(CPU::ticksPerSec); constexpr double nsPerTick = ticksPerSec / 1000000000.0; const s64 elapsedNs = s64(double(elapsedTicks) * nsPerTick); // Timer has fired if (elapsedNs >= timer->currentDelay) { timer->startTick = currentTicks; timer->currentDelay = timer->interval; signalTimer(handle, timer); } } } void Kernel::cancelTimer(Timer* timer) { timer->running = false; // TODO: When we have a scheduler this should properly cancel timer events in the scheduler } void Kernel::signalTimer(Handle timerHandle, Timer* timer) { timer->fired = true; requireReschedule(); // Check if there's any thread waiting on this event if (timer->waitlist != 0) { wakeupAllThreads(timer->waitlist, timerHandle); timer->waitlist = 0; // No threads waiting; switch (timer->resetType) { case ResetType::OneShot: timer->fired = false; break; case ResetType::Sticky: break; case ResetType::Pulse: Helpers::panic("Signalled pulsing timer"); break; } } } void Kernel::svcCreateTimer() { const u32 resetType = regs[1]; if (resetType > 2) { Helpers::panic("Invalid reset type for event %d", resetType); } // Have a warning here until our timers don't suck Helpers::warn("Called Kernel::CreateTimer. Timers are currently not updated nor triggered properly!"); logSVC("CreateTimer (resetType = %s)\n", resetTypeToString(resetType)); regs[0] = Result::Success; regs[1] = makeTimer(static_cast(resetType)); } void Kernel::svcSetTimer() { Handle handle = regs[0]; // TODO: Is this actually s64 or u64? 3DBrew says s64, but u64 makes more sense const s64 initial = s64(u64(regs[1]) | (u64(regs[2]) << 32)); const s64 interval = s64(u64(regs[3]) | (u64(regs[4]) << 32)); logSVC("SetTimer (handle = %X, initial delay = %llX, interval delay = %llX)\n", handle, initial, interval); KernelObject* object = getObject(handle, KernelObjectType::Timer); if (object == nullptr) { Helpers::panic("Tried to set non-existent timer %X\n", handle); regs[0] = Result::Kernel::InvalidHandle; } Timer* timer = object->getData(); cancelTimer(timer); timer->currentDelay = initial; timer->interval = interval; timer->running = true; timer->startTick = cpu.getTicks(); // If the initial delay is 0 then instantly signal the timer if (initial == 0) { signalTimer(handle, timer); } else { // This should schedule an event in the scheduler when we have one } regs[0] = Result::Success; } void Kernel::svcClearTimer() { Handle handle = regs[0]; logSVC("ClearTimer (handle = %X)\n", handle); KernelObject* object = getObject(handle, KernelObjectType::Timer); if (object == nullptr) { Helpers::panic("Tried to clear non-existent timer %X\n", handle); regs[0] = Result::Kernel::InvalidHandle; } else { object->getData()->fired = false; regs[0] = Result::Success; } } void Kernel::svcCancelTimer() { Handle handle = regs[0]; logSVC("CancelTimer (handle = %X)\n", handle); KernelObject* object = getObject(handle, KernelObjectType::Timer); if (object == nullptr) { Helpers::panic("Tried to cancel non-existent timer %X\n", handle); regs[0] = Result::Kernel::InvalidHandle; } else { cancelTimer(object->getData()); regs[0] = Result::Success; } }