Kernel: HPET is now used in legacy mode when PIC is forced

This commit is contained in:
Bananymous 2023-08-10 22:01:30 +03:00
parent 8b57edde6b
commit 03d4b47f63
5 changed files with 41 additions and 29 deletions

View File

@ -8,14 +8,14 @@ namespace Kernel
class HPET final : public Timer
{
public:
static BAN::ErrorOr<BAN::UniqPtr<HPET>> create();
static BAN::ErrorOr<BAN::UniqPtr<HPET>> create(bool force_pic);
virtual uint64_t ms_since_boot() const override;
virtual timespec time_since_boot() const override;
private:
HPET() = default;
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize(bool force_pic);
void write_register(ptrdiff_t reg, uint64_t value) const;
uint64_t read_register(ptrdiff_t reg) const;

View File

@ -18,7 +18,7 @@ namespace Kernel
class SystemTimer : public Timer
{
public:
static void initialize();
static void initialize(bool force_pic);
static SystemTimer& get();
static bool is_initialized();
@ -32,7 +32,7 @@ namespace Kernel
private:
SystemTimer() = default;
void initialize_timers();
void initialize_timers(bool force_pic);
private:
uint64_t m_boot_time { 0 };

View File

@ -31,12 +31,12 @@
namespace Kernel
{
BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create()
BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create(bool force_pic)
{
HPET* hpet = new HPET();
if (hpet == nullptr)
return BAN::Error::from_errno(ENOMEM);
if (auto ret = hpet->initialize(); ret.is_error())
if (auto ret = hpet->initialize(force_pic); ret.is_error())
{
delete hpet;
return ret.release_error();
@ -44,7 +44,7 @@ namespace Kernel
return BAN::UniqPtr<HPET>::adopt(hpet);
}
BAN::ErrorOr<void> HPET::initialize()
BAN::ErrorOr<void> HPET::initialize(bool force_pic)
{
auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET");
if (header == nullptr)
@ -53,7 +53,7 @@ namespace Kernel
if (header->hardware_rev_id == 0)
return BAN::Error::from_errno(EINVAL);
if (!header->legacy_replacement_irq_routing_cable)
if (force_pic && !header->legacy_replacement_irq_routing_cable)
{
dwarnln("HPET doesn't support legacy mapping");
return BAN::Error::from_errno(ENOTSUP);
@ -92,26 +92,38 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP);
}
uint32_t irq_cap = timer0_config >> 32;
if (irq_cap == 0)
{
dwarnln("HPET doesn't have any interrupts available");
return BAN::Error::from_errno(EINVAL);
}
int irq = 0;
for (; irq < 32; irq++)
if (irq_cap & (1 << irq))
break;
if (!force_pic)
{
uint32_t irq_cap = timer0_config >> 32;
if (irq_cap == 0)
{
dwarnln("HPET doesn't have any interrupts available");
return BAN::Error::from_errno(EINVAL);
}
for (irq = 0; irq < 32; irq++)
if (irq_cap & (1 << irq))
break;
}
unmapper.disable();
uint64_t main_flags = HPET_CONFIG_ENABLE;
if (force_pic)
main_flags |= HPET_CONFIG_LEG_RT;
// Enable main counter
write_register(HPET_REG_CONFIG, read_register(HPET_REG_CONFIG) | HPET_CONFIG_ENABLE);
write_register(HPET_REG_CONFIG, read_register(HPET_REG_CONFIG) | main_flags);
uint64_t timer0_flags = 0;
timer0_flags |= HPET_Tn_INT_ENB_CNF;
timer0_flags |= HPET_Tn_TYPE_CNF;
timer0_flags |= HPET_Tn_VAL_SET_CNF;
if (!force_pic)
timer0_flags |= irq << HPET_Tn_INT_ROUTE_CNF_SHIFT;
// Enable timer 0 as 1 ms periodic
write_register(HPET_REG_TIMER_CONFIG(0), HPET_Tn_INT_ENB_CNF | HPET_Tn_TYPE_CNF | HPET_Tn_VAL_SET_CNF | (irq << HPET_Tn_INT_ROUTE_CNF_SHIFT));
write_register(HPET_REG_TIMER_CONFIG(0), timer0_flags);
write_register(HPET_REG_TIMER_COMPARATOR(0), read_register(HPET_REG_COUNTER) + ticks_per_ms);
write_register(HPET_REG_TIMER_COMPARATOR(0), ticks_per_ms);

View File

@ -8,12 +8,12 @@ namespace Kernel
static SystemTimer* s_instance = nullptr;
void SystemTimer::initialize()
void SystemTimer::initialize(bool force_pic)
{
ASSERT(s_instance == nullptr);
auto* temp = new SystemTimer;
ASSERT(temp);
temp->initialize_timers();
temp->initialize_timers(force_pic);
s_instance = temp;
}
@ -28,12 +28,12 @@ namespace Kernel
return !!s_instance;
}
void SystemTimer::initialize_timers()
void SystemTimer::initialize_timers(bool force_pic)
{
m_rtc = MUST(BAN::UniqPtr<RTC>::create());
m_boot_time = BAN::to_unix_time(m_rtc->get_current_time());
if (auto res = HPET::create(); res.is_error())
if (auto res = HPET::create(force_pic); res.is_error())
dwarnln("HPET: {}", res.error());
else
{

View File

@ -141,10 +141,13 @@ extern "C" void kernel_main()
MUST(ACPI::initialize());
dprintln("ACPI initialized");
parse_command_line();
dprintln("command line parsed, root='{}'", cmdline.root);
InterruptController::initialize(cmdline.force_pic);
dprintln("Interrupt controller initialized");
SystemTimer::initialize();
SystemTimer::initialize(cmdline.force_pic);
dprintln("Timers initialized");
DevFileSystem::initialize();
@ -154,9 +157,6 @@ extern "C" void kernel_main()
ASSERT(tty1);
dprintln("TTY initialized");
parse_command_line();
dprintln("command line parsed, root='{}'", cmdline.root);
MUST(Scheduler::initialize());
dprintln("Scheduler initialized");