]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Handle interrupts
authorDuje Mihanović <duje.mihanovic@skole.hr>
Wed, 22 Sep 2021 20:15:40 +0000 (22:15 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Thu, 14 Oct 2021 20:01:56 +0000 (22:01 +0200)
Currently handles exception 8 and IRQ 1. EXC8 is double fault, and IRQ1 is
keyboard. EXC8 handler puts out a ':(' on the top left corner of the screen and
halts the machine, while IRQ1 puts out a string on the screen. However, it will
only do so once, and I have yet to figure out why.

Makefile
include/arch/x86/io.h
include/arch/x86/irq/i8259a.h [new file with mode: 0644]
include/arch/x86/irq/idt.h [new file with mode: 0644]
kernel/arch/x86/irq/idt.c [new file with mode: 0644]
kernel/arch/x86/irq/sample_handler.c [new file with mode: 0644]
kernel/drivers/irq/i8259a.c [new file with mode: 0644]
kernel/kernel.c

index 5d9822946a116ea2bce52b0cef027cdbf59832d9..c8f15f3d53be49549e5fb28c3afa609bef1e7536 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,9 @@ AS = yasm
 LD = i686-elf-ld
 CC = i686-elf-gcc
 
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/kernel.o
+GIT_REV = $(shell git rev-parse --short HEAD)
+
+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
 
 all: boot.img kernel/kernel.elf
 
@@ -20,10 +22,19 @@ kernel/entry.o: kernel/entry.s
        $(AS) -f elf kernel/entry.s -o $@
 
 kernel/arch/x86/tty/tty.o: kernel/arch/x86/tty/tty.c
-       $(CC) -g -o $@ -Iinclude/arch/x86 -ffreestanding -c kernel/arch/x86/tty/tty.c
+       $(CC) -std=gnu89 -g -o $@ -Iinclude/arch/x86 -ffreestanding -c kernel/arch/x86/tty/tty.c
+
+kernel/drivers/irq/i8259a.o: kernel/drivers/irq/i8259a.c
+       $(CC) -std=gnu89 -g -o $@ -Iinclude/arch/x86 -ffreestanding -c kernel/drivers/irq/i8259a.c
+
+kernel/arch/x86/irq/idt.o: kernel/arch/x86/irq/idt.c
+       $(CC) -std=gnu89 -g -o $@ -Iinclude/arch/x86 -ffreestanding -c kernel/arch/x86/irq/idt.c
+
+kernel/arch/x86/irq/sample_handler.o: kernel/arch/x86/irq/sample_handler.c
+       $(CC) -std=gnu89 -g -o $@ -Iinclude/arch/x86 -ffreestanding -mgeneral-regs-only -c kernel/arch/x86/irq/sample_handler.c
 
 kernel/kernel.o: kernel/kernel.c
-       $(CC) -g -o $@ -Iinclude/arch/x86 -ffreestanding -c kernel/kernel.c
+       $(CC) -std=gnu89 -g -o $@ -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\" -c kernel/kernel.c
 
 kernel/kernel.elf: kernel/kernel.bin
        $(LD) -o $@ -T kernel/linker.ld ${KERNEL_OBJ} --oformat=elf32-i386
index 586eb7445e76aa5bade5cbdd2a71eb9f8fb7d513..09f6fa7dcf38c10f20202abaa71a38efca20029c 100644 (file)
@@ -17,4 +17,9 @@ static inline uint8_t inb(uint16_t port)
        return ret;
 }
 
+static inline void io_wait(void)
+{
+       inb(0x80);
+}
+
 #endif
diff --git a/include/arch/x86/irq/i8259a.h b/include/arch/x86/irq/i8259a.h
new file mode 100644 (file)
index 0000000..31448e4
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef X86_I8259A_H
+#define X86_I8259A_H
+
+#define PIC1_COMMAND 0x20
+#define PIC1_DATA 0x21
+#define PIC2_COMMAND 0xA0
+#define PIC2_DATA 0xA1
+
+#define PIC_ICW1_INIT 0x10
+#define PIC_ICW1_ICW4 0x1
+
+#define PIC_ICW4_8086 0x1
+
+#define PIC_EOI 0x20
+
+extern void pic_init(int offset1, int offset2);
+extern void pic_mask(uint8_t irq);
+extern void pic_unmask(uint8_t irq);
+extern void pic_mask_all(void);
+extern void pic_unmask_all(void);
+extern void pic_send_eoi(uint8_t irq);
+
+#endif
diff --git a/include/arch/x86/irq/idt.h b/include/arch/x86/irq/idt.h
new file mode 100644 (file)
index 0000000..8b2efa1
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef X86_IDT_H
+#define X86_IDT_H
+
+#include <stdint.h>
+
+#define IDT_VECTOR_COUNT 256 /* our IDT will have 256 vectors */
+#define IDT_DESCRIPTOR_SIZE 8 /* each IDT descriptor is 8 bytes long */
+
+#define IDT_TRAP_GATE          0x1F
+#define IDT_INTERRUPT_GATE     0x0E
+
+struct idt_descriptor {
+       uint16_t offset_1; /* bits 0-15 of offset */
+       uint16_t segsel; /* segment selector */
+       unsigned unused : 8, type : 5, dpl : 2, present : 1;
+       uint16_t offset_2; /* bits 16-31 of offset */
+} __attribute__((packed));
+
+struct idtr {
+       uint16_t limit; /* size of IDT minus 1 */
+       uint32_t base; /* starting address of IDT */
+} __attribute__((packed));
+
+extern void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, uint32_t offset, uint8_t type, uint8_t dpl);
+extern inline void load_idt(struct idtr idtr);
+extern inline void populate_idtr(struct idtr *idtr, struct idt_descriptor *idt);
+
+#endif
diff --git a/kernel/arch/x86/irq/idt.c b/kernel/arch/x86/irq/idt.c
new file mode 100644 (file)
index 0000000..54e8612
--- /dev/null
@@ -0,0 +1,27 @@
+#include <irq/idt.h>
+#include <stdint.h>
+
+/* Note to self: passing a pointer to an asm constraint as "m" will give a pointer to pointer */
+inline void load_idt(struct idtr idtr)
+{
+       asm volatile ("lidt %0": : "m" (idtr));
+}
+
+void idt_set_descriptor(struct idt_descriptor *idt, uint8_t vector, uint16_t segment, uint32_t offset, uint8_t type, uint8_t dpl)
+{
+       struct idt_descriptor *descriptor = &idt[vector];
+
+       descriptor->offset_1 = offset & 0xFFFF;
+       descriptor->segsel = segment;
+       descriptor->unused = 0;
+       descriptor->type = type;
+       descriptor->dpl = dpl;
+       descriptor->present = 1;
+       descriptor->offset_2 = offset >> 16;
+}
+
+inline void populate_idtr(struct idtr *idtr, struct idt_descriptor *idt)
+{
+       idtr->limit = ((IDT_VECTOR_COUNT * IDT_DESCRIPTOR_SIZE) - 1); /* limit must be size - 1 */
+       idtr->base = (uint32_t) idt;
+}
diff --git a/kernel/arch/x86/irq/sample_handler.c b/kernel/arch/x86/irq/sample_handler.c
new file mode 100644 (file)
index 0000000..c8bddfe
--- /dev/null
@@ -0,0 +1,30 @@
+#include <tty.h>
+#include <irq/i8259a.h>
+#include <stdint.h>
+
+typedef uint32_t uword_t;
+
+struct interrupt_frame {
+       uword_t ip;
+       uword_t cs;
+       uword_t flags;
+};
+
+struct abort_frame;
+
+__attribute__((interrupt))
+void keyb_handler(struct interrupt_frame *frame)
+{
+       pic_send_eoi(1);
+       kprint("Got a keyboard interrupt!\n", 0);
+}
+
+
+__attribute__((interrupt))
+void double_fault(struct abort_frame *frame)
+{
+       *(volatile char *) (0xb8000) = ":";
+       *(volatile char *) (0xb8002) = "(";
+       asm volatile ("cli; hlt");
+}
+
diff --git a/kernel/drivers/irq/i8259a.c b/kernel/drivers/irq/i8259a.c
new file mode 100644 (file)
index 0000000..ed1e6ac
--- /dev/null
@@ -0,0 +1,80 @@
+#include <io.h>
+#include <tty.h>
+#include <irq/i8259a.h>
+
+void pic_init(int offset1, int offset2)
+{
+       uint8_t a1, a2;
+
+       a1 = inb(PIC1_DATA);
+       a2 = inb(PIC2_DATA);
+
+       outb(PIC1_COMMAND, PIC_ICW1_INIT | PIC_ICW1_ICW4);
+       io_wait();
+       outb(PIC2_COMMAND, PIC_ICW1_INIT | PIC_ICW1_ICW4);
+       io_wait();
+       outb(PIC1_DATA, offset1);
+       io_wait();
+       outb(PIC2_DATA, offset2);
+       io_wait();
+       outb(PIC1_DATA, 4);
+       io_wait();
+       outb(PIC2_DATA, 2);
+       io_wait();
+
+       outb(PIC1_DATA, PIC_ICW4_8086);
+       io_wait();
+       outb(PIC2_DATA, PIC_ICW4_8086);
+       io_wait();
+
+       outb(PIC1_DATA, a1);
+       outb(PIC2_DATA, a2);
+}
+
+void pic_mask(uint8_t irq)
+{
+       uint16_t port;
+       uint8_t value;
+
+       if (irq < 8) {
+               port = PIC1_DATA;
+       } else {
+               port = PIC2_DATA;
+       }
+
+       value = inb(port) | (1 << irq);
+       outb(port, value);
+}
+
+void pic_unmask(uint8_t irq)
+{
+       uint16_t port;
+       uint8_t value;
+
+       if (irq < 8) {
+               port = PIC1_DATA;
+       } else {
+               port = PIC2_DATA;
+       }
+
+       value = inb(port) & ~(1 << irq);
+       outb(port, value);
+}
+
+void pic_mask_all(void)
+{
+       outb(PIC1_DATA, 0xFF);
+}
+
+void pic_unmask_all(void)
+{
+       outb(PIC1_DATA, 0);
+}
+
+void pic_send_eoi(uint8_t irq)
+{
+       if (irq >= 8)
+               outb(PIC2_COMMAND, PIC_EOI);
+
+       outb(PIC1_COMMAND, PIC_EOI);
+}
index 7b6d3543c39066879672e1b44acfc357b8a9f2d9..e1a0df5158f3b06bfd44e8693db172d431737dbf 100644 (file)
@@ -1,39 +1,31 @@
 #include <tty.h>
 #include <io.h>
+#include <irq/idt.h>
+#include <irq/i8259a.h>
 #include <stdint.h>
 
-const char *string = "Hello there!\n\n\
-Hopefully your machine manages to print this text.\n\
-If it did, that's great news because I managed to write a partial VGA driver.\n\n\
-Right now, the short-term roadmap is as follows:\n\n\
-* Complete the text-mode part of the VGA driver.\n\
-* Enable interrupts using the PIC.\n\
-* Write a driver for the Intel 8042 PS/2 controller so the OS can receive keystrokes.\n\
-* Once all that is done, it would be desirable to start the switch to userspace so the OS can actually be remotely usable.\n\n\
-Feel free to mess around with the code, although I doubt it will be very interesting at the moment.\n";
+extern void double_fault(struct abort_frame *frame);
+extern void keyb_handler(struct interrupt_frame *frame);
+struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
+struct idtr idtr __attribute__((aligned(0x10)));
 
 void _start(void)
 {
        screen_clear();
-       /*kprint(string, 0x07);*/
-       kprint("Color 0x01\n", VGA_COLOR_BLUE);
-       kprint("Color 0x02\n", VGA_COLOR_GREEN);
-       kprint("Color 0x03\n", VGA_COLOR_TEAL);
-       kprint("Color 0x04\n", VGA_COLOR_DARK_RED);
-       kprint("Color 0x05\n", VGA_COLOR_MAGENTA);
-       kprint("Color 0x06\n", VGA_COLOR_BROWN);
-       kprint("Color 0x07\n", VGA_COLOR_LIGHT_GRAY);
-       kprint("Color 0x08\n", VGA_COLOR_DARK_GRAY);
-       kprint("Color 0x09\n", VGA_COLOR_PURPLE);
-       kprint("Color 0x0A\n", VGA_COLOR_LIME);
-       kprint("Color 0x0B\n", VGA_COLOR_CYAN);
-       kprint("Color 0x0C\n", VGA_COLOR_BRIGHT_RED);
-       kprint("Color 0x0D\n", VGA_COLOR_PINK);
-       kprint("Color 0x0E\n", VGA_COLOR_YELLOW);
-       kprint("Color 0x0F\n", VGA_COLOR_WHITE);
-       kprintb(0xAE);
+       kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
+       kprint(GIT_COMMIT, 0);
        kprint("\n", 0);
-       kprintw(0xDEAD);
-       kprint("\n", 0);
-       kprintd(0x89ABCDEF);
+       kprint("Preparing IDT...\n", 0);
+       idt_set_descriptor(idt, 0x8, 0x8, (uint32_t) double_fault, IDT_TRAP_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);
+       load_idt(idtr);
+       kprint("IDT loaded, enabling interrupts...\n", 0);
+       pic_init(0x20, 0x28);
+       pic_mask_all();
+       pic_unmask(1);
+       asm volatile ("sti");
+       kprint("All done\n", 0);
+       while(1);
 }