From 629dca278b4ff853ec63b3745c85b2265f624746 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 29 May 2023 21:52:01 -0700 Subject: [PATCH] Enable the PIC and add a timer. This causes a GP fault after the timer runs for some time. --- zion/CMakeLists.txt | 1 + zion/interrupt/interrupt.cpp | 25 +++++++++++++++++++ zion/interrupt/interrupt_enter.s | 2 ++ zion/interrupt/timer.cpp | 41 ++++++++++++++++++++++++++++++++ zion/interrupt/timer.h | 5 ++++ zion/zion.cpp | 2 ++ 6 files changed, 76 insertions(+) create mode 100644 zion/interrupt/timer.cpp create mode 100644 zion/interrupt/timer.h diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 2b35ec3..b4bc251 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(zion debug/debug.cpp interrupt/interrupt.cpp interrupt/interrupt_enter.s + interrupt/timer.cpp loader/elf_loader.cpp loader/init_loader.cpp memory/kernel_heap.cpp diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index ca07e92..87b83ab 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -2,6 +2,7 @@ #include +#include "common/port.h" #include "debug/debug.h" #define IDT_INTERRUPT_GATE 0x8E @@ -95,13 +96,37 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) { panic("PF"); } +#define PIC1_COMMAND 0x20 +#define PIC1_DATA 0x21 +#define PIC_EOI 0x20 + +uint64_t cnt = 0; +extern "C" void isr_timer(); +extern "C" void interrupt_timer(InterruptFrame*) { + cnt++; + if (cnt % 1000 == 0) { + dbgln("timer: %u", cnt); + } + outb(PIC1_COMMAND, PIC_EOI); +} + +void EnablePic() { + outb(PIC1_COMMAND, 0x11); + outb(PIC1_DATA, 0x20); // PIC1 offset. + outb(PIC1_DATA, 0x4); + outb(PIC1_DATA, 0x1); +} + void InitIdt() { gIdt[0] = CreateDescriptor(isr_divide_by_zero); gIdt[13] = CreateDescriptor(isr_protection_fault); gIdt[14] = CreateDescriptor(isr_page_fault); + gIdt[32] = CreateDescriptor(isr_timer); InterruptDescriptorTablePointer idtp{ .size = sizeof(gIdt), .base = reinterpret_cast(gIdt), }; asm volatile("lidt %0" ::"m"(idtp)); + + EnablePic(); } diff --git a/zion/interrupt/interrupt_enter.s b/zion/interrupt/interrupt_enter.s index 92b41a6..cf6db7a 100644 --- a/zion/interrupt/interrupt_enter.s +++ b/zion/interrupt/interrupt_enter.s @@ -55,3 +55,5 @@ isr_\name: isr_handler divide_by_zero isr_handler protection_fault,1 isr_handler page_fault,1 + +isr_handler timer diff --git a/zion/interrupt/timer.cpp b/zion/interrupt/timer.cpp new file mode 100644 index 0000000..392dfd6 --- /dev/null +++ b/zion/interrupt/timer.cpp @@ -0,0 +1,41 @@ +#include "interrupt/timer.h" + +#include "common/port.h" + +namespace { + +// IO Ports +constexpr uint8_t kPit0Ctl = 0x40; +constexpr uint8_t kPit1Ctl = 0x41; +constexpr uint8_t kPit2Ctl = 0x42; +constexpr uint8_t kPitCmd = 0x43; + +// Command Register +// Mode +constexpr uint8_t kPitMode0 = 0x00; +constexpr uint8_t kPitMode1 = 0x02; +constexpr uint8_t kPitMode2 = 0x04; +constexpr uint8_t kPitMode3 = 0x06; +constexpr uint8_t kPitMode4 = 0x08; +constexpr uint8_t kPitMode5 = 0x0A; +// R/W +constexpr uint8_t kCmdLatch = 0x00; +constexpr uint8_t kCmdRwLow = 0x10; +constexpr uint8_t kCmdRwHi = 0x20; +constexpr uint8_t kCmdRwBoth = 0x30; +// PIT Select +constexpr uint8_t kSelect0 = 0x00; +constexpr uint8_t kSelect1 = 0x40; +constexpr uint8_t kSelect2 = 0x80; +constexpr uint8_t kReadback = 0xC0; + +constexpr uint32_t kPitFrequency = 1193182; + +} // namespace + +void SetFrequency(uint64_t hertz) { + uint16_t reload = kPitFrequency / hertz; + outb(kPitCmd, kPitMode3 | kCmdRwBoth | kSelect0); + outb(kPit0Ctl, reload & 0xFF); + outb(kPit0Ctl, reload >> 8); +} diff --git a/zion/interrupt/timer.h b/zion/interrupt/timer.h new file mode 100644 index 0000000..f227aa0 --- /dev/null +++ b/zion/interrupt/timer.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void SetFrequency(uint64_t hertz); diff --git a/zion/zion.cpp b/zion/zion.cpp index dfc270d..d872cc9 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -3,6 +3,7 @@ #include "common/gdt.h" #include "debug/debug.h" #include "interrupt/interrupt.h" +#include "interrupt/timer.h" #include "loader/init_loader.h" #include "memory/kernel_heap.h" #include "memory/paging_util.h" @@ -21,6 +22,7 @@ extern "C" void zion() { InitSyscall(); + SetFrequency(/* hertz= */ 2000); sched::InitScheduler(); sched::EnableScheduler();