]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Add Intel 8254 driver and print elapsed seconds timing origin/timing
authorDuje Mihanović <duje.mihanovic@skole.hr>
Sat, 14 May 2022 11:22:39 +0000 (13:22 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Wed, 22 Jun 2022 16:06:28 +0000 (18:06 +0200)
Makefile
include/arch/x86/time/i8254.h [new file with mode: 0644]
include/arch/x86/tty.h
kernel/arch/x86/irq/sample_handler.c
kernel/arch/x86/time/i8254.c [new file with mode: 0644]
kernel/arch/x86/tty/tty.c
kernel/kernel.c

index f5a33b6d70eec5a59eb84b17b34bf3dfd92b1dfe..5373d0b68cdac635b8a341273c5b0984907c8088 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ export GIT_REV = $(shell git describe --long HEAD)
 
 CFLAGS = -std=gnu99 -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
 
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/arch/x86/time/i8254.o kernel/kernel.o
 BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN
 
 default: kernel/kernel.elf bootloader
diff --git a/include/arch/x86/time/i8254.h b/include/arch/x86/time/i8254.h
new file mode 100644 (file)
index 0000000..18a8546
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef X86_I8254_H
+#define X86_I8254_H
+
+#include <stdint.h>
+#include <io.h>
+#include <irq/i8259a.h>
+
+/* for setting reload value and reading current count */
+#define PORT_CHANNEL_0_DATA    0x40
+#define PORT_CHANNEL_1_DATA    0x41
+#define PORT_CHANNEL_2_DATA    0x42
+
+/* for configuring the channels */
+#define PORT_MODE_CMD_REG      0x43
+
+/* operating modes */
+#define INT_ON_TERM_CNT                0x0
+#define HW_RETRIGGER_ONESHOT   0x1
+#define RATE_GENERATOR         0x2
+#define SQUARE_WAVE_GENERATOR  0x3
+#define SW_TRIGGERED_STROBE    0x4
+#define HW_TRIGGERED_STROBE    0x5
+
+/* access modes */
+#define        ACMODE_COUNTER_LATCH_CMD        0x0
+#define ACMODE_LSB_ONLY                        0x1
+#define ACMODE_MSB_ONLY                        0x2
+#define ACMODE_LSB_MSB                 0x3
+
+union mode_command {
+       struct {
+               unsigned bcd: 1, /* if set, uses BCD for reload value */
+                        opmode: 3, /* operating mode */
+                        acmode: 2, /* access mode */
+                        channel: 2; /* channel to configure */
+       } fields;
+       uint8_t command;
+};
+
+extern unsigned int ticks;
+extern uint16_t reload;
+
+extern void i8254_configure_channel(char channel, char opmode, uint16_t new_reload);
+extern void i8254_irq_enable();
+
+#endif
index 42857acc4c68cbfd5cc5238c492c7688b100d26d..d1d317156045fb7d88c73f91e4951c26f92a2768 100644 (file)
 
 extern void screen_clear(void);
 extern void kprint(const char *string, uint8_t color);
+extern void kprints(const char *string, uint8_t color);
 extern void kprintb(const uint8_t byte);
 extern void kprintw(const uint16_t word);
 extern void kprintd(const uint32_t dword);
+extern void kprintc(const char character, uint8_t color);
 extern int kprintdec(uint32_t num);
 #endif
index f4f4a4bfefad5aacf742f3c6ce2046c86eb1b85e..be6829871d68c1b0845f2832962302c4f637f259 100644 (file)
@@ -2,6 +2,9 @@
 #include <irq/i8259a.h>
 #include <io.h>
 #include <stdint.h>
+#include <time/i8254.h>
+
+unsigned int ticks = 0;
 
 typedef uint32_t uword_t;
 
@@ -31,3 +34,10 @@ halt:
        goto halt;
 }
 
+
+__attribute__((interrupt))
+void timer_tick(struct interrupt_frame *frame)
+{
+       pic_send_eoi(0);
+       ticks++;
+}
diff --git a/kernel/arch/x86/time/i8254.c b/kernel/arch/x86/time/i8254.c
new file mode 100644 (file)
index 0000000..d205f11
--- /dev/null
@@ -0,0 +1,37 @@
+#include <time/i8254.h>
+
+uint16_t reload;
+
+void i8254_configure_channel(char channel, char opmode, uint16_t new_reload)
+{
+       union mode_command command;
+
+       command.fields.bcd = 0;
+       command.fields.channel = channel;
+       command.fields.acmode = ACMODE_LSB_MSB;
+       command.fields.opmode = opmode;
+
+       outb(PORT_MODE_CMD_REG, command.command);
+
+       switch (channel) {
+               case 0:
+                       outb(PORT_CHANNEL_0_DATA, new_reload & 0xff);
+                       outb(PORT_CHANNEL_0_DATA, new_reload >> 8);
+                       break;
+               case 1:
+                       outb(PORT_CHANNEL_1_DATA, new_reload & 0xff);
+                       outb(PORT_CHANNEL_1_DATA, new_reload >> 8);
+                       break;
+               case 2:
+                       outb(PORT_CHANNEL_2_DATA, new_reload & 0xff);
+                       outb(PORT_CHANNEL_2_DATA, new_reload >> 8);
+                       break;
+       }
+
+       reload = new_reload;
+}
+
+void i8254_irq_enable()
+{
+       pic_unmask(0);
+}
index 51686a3c8901c3a4f56b2a8ead3e834624b048a4..83678b0684f48169aef5634c01bf13b1db04a04c 100644 (file)
@@ -1,6 +1,7 @@
 #include <io.h>
 #include <tty.h>
 #include <stdint.h>
+#include <time/i8254.h>
 
 #define VGA_WIDTH 80
 #define VGA_HEIGHT 25
@@ -41,6 +42,14 @@ void scroll_up(void)
 }
 
 void kprint(const char *string, uint8_t color)
+{
+       kprintc('[', 0);
+       kprintdec(ticks / (1193182 / 65536));
+       kprints("] ", 0);
+       kprints(string, color);
+}
+
+void kprints(const char *string, uint8_t color)
 {
        char next_char;
        uint8_t vga_misc_output;
@@ -142,11 +151,18 @@ int kprintdec(uint32_t num)
 {
        char buffer[11];
        int digits = 10;
+
        /* TODO: make an actual memset function to use instead of this */
        for (int i=0; i<11; i++) {
                buffer[i] = 0;
        }
 
+       /* handle edge case */
+       if (num==0) {
+               *buffer = '0';
+               goto print;
+       }
+
        /* put the numbers in the buffer */
        for (int i=9; i>0 && num>0; i--) {
                uint8_t currdigit = num%10;
@@ -169,6 +185,7 @@ int kprintdec(uint32_t num)
                }
        }
 
-       kprint(buffer, 0);
+print:
+       kprints(buffer, 0);
        return digits;
 }
index 24deeb9cb9d474fb1e465e27b96ecb5ae0cd6a6a..35100f1d24a54e6e95b3b23b48a09d7115b08526 100644 (file)
@@ -2,21 +2,25 @@
 #include <io.h>
 #include <irq/idt.h>
 #include <irq/i8259a.h>
+#include <time/i8254.h>
 #include <stdint.h>
 
 extern void double_fault(struct abort_frame *frame);
 extern void keyb_handler(struct interrupt_frame *frame);
+extern void timer_tick(struct interrupt_frame *frame);
 struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
 struct idtr idtr __attribute__((aligned(0x10)));
 
 void kmain(void)
 {
+       ticks = 0;
        screen_clear();
        kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
        kprint(GIT_COMMIT, 0);
        kprint("\n", 0);
        kprint("Preparing IDT...\n", 0);
        idt_set_descriptor(idt, 0x8, 0x8, (uint32_t) double_fault, IDT_TRAP_GATE, 0x0);
+       idt_set_descriptor(idt, 0x20, 0x8, (uint32_t) timer_tick, IDT_INTERRUPT_GATE, 0x0);
        idt_set_descriptor(idt, 0x21, 0x8, (uint32_t) keyb_handler, IDT_INTERRUPT_GATE, 0x0);
        kprint("IDT prepared, loading...\n", 0);
        populate_idtr(&idtr, idt);
@@ -26,10 +30,9 @@ void kmain(void)
        pic_mask_all();
        pic_unmask(1);
        asm volatile ("sti");
+       kprint("Setting up timer...\n", 0);
+       i8254_configure_channel(0, SQUARE_WAVE_GENERATOR, 0);
+       i8254_irq_enable();
        kprint("All done\n", 0);
-       kprintdec(12345);
-       kprintc('\n');
-       kprintdec(6789);
-       kprintc('\n');
        while(1);
 }