forked from Bananymous/banan-os
Kernel: Start work on abstracting Timers
This commit is contained in:
73
kernel/kernel/Timer/PIT.cpp
Normal file
73
kernel/kernel/Timer/PIT.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/PIT.h>
|
||||
|
||||
#define TIMER0_CTL 0x40
|
||||
#define TIMER1_CTL 0x41
|
||||
#define TIMER2_CTL 0x42
|
||||
#define PIT_CTL 0x43
|
||||
|
||||
#define SELECT_CHANNEL0 0x00
|
||||
#define SELECT_CHANNEL1 0x40
|
||||
#define SELECT_CHANNEL2 0x80
|
||||
|
||||
#define ACCESS_HI 0x10
|
||||
#define ACCESS_LO 0x20
|
||||
|
||||
#define MODE_SQUARE_WAVE 0x06
|
||||
|
||||
#define BASE_FREQUENCY 1193182
|
||||
#define TICKS_PER_SECOND 1000
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static volatile uint64_t s_system_time = 0;
|
||||
|
||||
void irq_handler()
|
||||
{
|
||||
s_system_time = s_system_time + 1;
|
||||
Kernel::Scheduler::get().timer_reschedule();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<PIT>> PIT::create()
|
||||
{
|
||||
PIT* pit = new PIT;
|
||||
if (pit == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
pit->initialize();
|
||||
return BAN::UniqPtr<PIT>::adopt(pit);
|
||||
}
|
||||
|
||||
void PIT::initialize()
|
||||
{
|
||||
constexpr uint16_t timer_reload = BASE_FREQUENCY / TICKS_PER_SECOND;
|
||||
|
||||
IO::outb(PIT_CTL, SELECT_CHANNEL0 | ACCESS_LO | ACCESS_HI | MODE_SQUARE_WAVE);
|
||||
|
||||
IO::outb(TIMER0_CTL, (timer_reload >> 0) & 0xff);
|
||||
IO::outb(TIMER0_CTL, (timer_reload >> 8) & 0xff);
|
||||
|
||||
IDT::register_irq_handler(PIT_IRQ, irq_handler);
|
||||
|
||||
InterruptController::get().enable_irq(PIT_IRQ);
|
||||
}
|
||||
|
||||
uint64_t PIT::ms_since_boot() const
|
||||
{
|
||||
return s_system_time;
|
||||
}
|
||||
|
||||
void PIT::sleep(uint64_t ms) const
|
||||
{
|
||||
if (ms == 0)
|
||||
return;
|
||||
uint64_t wake_time = s_system_time + ms;
|
||||
Kernel::Scheduler::get().set_current_thread_sleeping(wake_time);
|
||||
if (s_system_time < wake_time)
|
||||
dwarnln("sleep woke {} ms too soon", wake_time - s_system_time);
|
||||
}
|
||||
|
||||
}
|
||||
51
kernel/kernel/Timer/Timer.cpp
Normal file
51
kernel/kernel/Timer/Timer.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/Timer/PIT.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static TimerHandler* s_instance = nullptr;
|
||||
|
||||
void TimerHandler::initialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
s_instance = new TimerHandler;
|
||||
ASSERT(s_instance);
|
||||
s_instance->initialize_timers();
|
||||
}
|
||||
|
||||
TimerHandler& TimerHandler::get()
|
||||
{
|
||||
ASSERT(s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
bool TimerHandler::is_initialized()
|
||||
{
|
||||
return !!s_instance;
|
||||
}
|
||||
|
||||
void TimerHandler::initialize_timers()
|
||||
{
|
||||
if (auto res = PIT::create(); res.is_error())
|
||||
dwarnln("PIT: {}", res.error());
|
||||
else
|
||||
{
|
||||
MUST(m_timers.emplace_back(BAN::move(res.release_value())));
|
||||
dprintln("PIT initialized");
|
||||
}
|
||||
|
||||
ASSERT(!m_timers.empty());
|
||||
}
|
||||
|
||||
uint64_t TimerHandler::ms_since_boot() const
|
||||
{
|
||||
return m_timers.front()->ms_since_boot();
|
||||
}
|
||||
|
||||
void TimerHandler::sleep(uint64_t ms) const
|
||||
{
|
||||
return m_timers.front()->sleep(ms);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user