From c84d214daa507fdc267acfc92b0895b417c9553a Mon Sep 17 00:00:00 2001 From: Alexander Myltsev Date: Wed, 25 Jan 2023 14:56:38 +0400 Subject: [PATCH] Add drivers/pit.c by 3Hren. --- Makefile | 2 +- drivers/pit.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pit.h | 8 ++++++ kernel.c | 7 +++++ 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 drivers/pit.c create mode 100644 drivers/pit.h diff --git a/Makefile b/Makefile index ab4d4f6..6593b63 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,7 @@ image.bin: mbr.bin fs.img kernel.bin: kernel.o console.o drivers/vga.o drivers/keyboard.o \ drivers/ata.o cpu/vectors.o cpu/idt.o cpu/gdt.o drivers/uart.o \ - fs/fs.o lib/mem.o lib/string.o proc.o cpu/swtch.o + fs/fs.o lib/mem.o lib/string.o proc.o cpu/swtch.o drivers/pit.o $(LD) $(LDFLAGS) $(LDKERNELFLAGS) -o $@ -Ttext 0x1000 $^ %.o: %.c diff --git a/drivers/pit.c b/drivers/pit.c new file mode 100644 index 0000000..7b8edc1 --- /dev/null +++ b/drivers/pit.c @@ -0,0 +1,76 @@ +#include "pit.h" +#include "port.h" +#include "../cpu/isr.h" + +enum { + PIT_CRYSTAL_HZ = 1193182, + + CLOCK_PRECISION_HZ = 100, + + PIT_PROGRAM_REG = PIT_CRYSTAL_HZ / CLOCK_PRECISION_HZ, + + PIT_SELECT_CHANNEL0 = 0x0, + PIT_SELECT_CHANNEL1 = 0x1, + PIT_SELECT_CHANNEL2 = 0x2, + PIT_SELECT_CHANNEL_RB = 0x3, + PIT_ACCESS_MODE_LATCH_COUNT_VALUE_COMMAND = 0x0, + PIT_ACCESS_MODE_LOBYTE_ONLY = 0x1, + PIT_ACCESS_MODE_HIBYTE_ONLY = 0x2, + PIT_ACCESS_MODE_LOHIBYTE = 0x3, + PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT = 0x0, + PIT_MODE_HW_ONESHOT = 0x1, + PIT_MODE_RATE_GENERATOR = 0x2, + PIT_MODES_SQUARE_WAVE_GENERATOR = 0x3, + PIT_MODES_SW_TRIGGERRED_STROBE = 0x4, + PIT_MODES_HW_TRIGGERRED_STROBE = 0x5, +}; + +static timer_callback callbacks[100]; +static int registered_callbacks = 0; + +void add_timer_callback(timer_callback tc) { + callbacks[registered_callbacks++] = tc; +} + +static void timer_interrupt_handler(registers_t *r) { + for (int i = 0; i < registered_callbacks; ++i) { + callbacks[i](); + } +} + +struct pit_command_t { + unsigned char bcd : 1; + unsigned char operating_mode : 3; + unsigned char access_mode : 2; + unsigned char select_channel : 2; +} __attribute__((packed)); + +static void dec_sleep_counter(void); + +void init_pit() { + struct pit_command_t cmd = { + .select_channel = PIT_SELECT_CHANNEL0, + .access_mode = PIT_ACCESS_MODE_LOHIBYTE, + .operating_mode = PIT_MODES_SQUARE_WAVE_GENERATOR, + .bcd = 0, + }; + port_byte_out(0x43, *(unsigned char *)(&cmd)); + port_byte_out(0x40, PIT_PROGRAM_REG & 0xff); + port_byte_out(0x40, (PIT_PROGRAM_REG & 0xff00) >> 8); + + register_interrupt_handler(IRQ0, timer_interrupt_handler); + add_timer_callback(dec_sleep_counter); +} + +static int sleep_counter = 0; + +static void dec_sleep_counter(void) { + sleep_counter--; +} + +void msleep(int ms) { + sleep_counter = ms / 10; + while (sleep_counter > 0) { + asm("hlt"); + } +} diff --git a/drivers/pit.h b/drivers/pit.h new file mode 100644 index 0000000..01b72ad --- /dev/null +++ b/drivers/pit.h @@ -0,0 +1,8 @@ +#pragma once + +typedef void (*timer_callback)(void); + +void init_pit(void); +void add_timer_callback(timer_callback tc); + +void msleep(int ms); diff --git a/kernel.c b/kernel.c index db26e72..e502a2c 100644 --- a/kernel.c +++ b/kernel.c @@ -7,6 +7,7 @@ asm(".asciz \"kernel start\\n\""); #include "drivers/vga.h" #include "drivers/ata.h" #include "drivers/misc.h" +#include "drivers/pit.h" #include "drivers/uart.h" #include "fs/fs.h" #include "lib/string.h" @@ -16,6 +17,7 @@ asm(".asciz \"kernel start\\n\""); void _start() { load_gdt(); init_keyboard(); + init_pit(); uartinit(); load_idt(); sti(); @@ -35,6 +37,11 @@ void _start() { if (kbd_buf_size > 0 && kbd_buf[kbd_buf_size-1] == '\n') { if (!strncmp("halt\n", kbd_buf, kbd_buf_size)) { qemu_shutdown(); + } else if (!strncmp("work\n", kbd_buf, kbd_buf_size)) { + for (int i = 0; i < 5; ++i) { + msleep(1000); + printk("."); + } } else if (!strncmp("run ", kbd_buf, 4)) { kbd_buf[kbd_buf_size-1] = '\0'; const char* cmd = kbd_buf + 4;