greatbridf 4 жил өмнө
parent
commit
1f23172be8

+ 3 - 0
CMakeLists.txt

@@ -10,6 +10,8 @@ file(MAKE_DIRECTORY ${EXTRACT_DIR})
 
 set(BOOTLOADER_SOURCES src/boot.s
                        src/asm/a20.s
+                       src/asm/interrupt.s
+                       src/asm/port_io.s
                        )
 
 add_library(bootloader STATIC ${BOOTLOADER_SOURCES})
@@ -31,6 +33,7 @@ set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         src/kernel/mem.c
                         src/kernel/vga.c
                         include/asm/boot.h
+                        include/asm/port_io.h
                         include/kernel/interrupt.h
                         include/kernel/stdio.h
                         include/kernel/mem.h

+ 5 - 0
include/asm/port_io.h

@@ -0,0 +1,5 @@
+#pragma once
+
+#include <types/types.h>
+
+extern void asm_outb(uint16_t port_number, uint8_t data);

+ 55 - 0
include/kernel/interrupt.h

@@ -0,0 +1,55 @@
+#pragma once
+
+#include <types/types.h>
+
+#define INTERRUPT_GATE_TYPE (0x8e)
+
+// external interrupt handler function
+// stub in assembly MUST be called irqN
+#define SET_UP_IRQ(N, SELECTOR)        \
+    extern void irq##N();              \
+    ptr_t addr_irq##N = (ptr_t)irq##N; \
+    SET_IDT_ENTRY(0x20 + (N), (addr_irq##N), (SELECTOR));
+
+#define SET_IDT_ENTRY(N, ADDR, SELECTOR)      \
+    IDT[(N)].offset_low = (ADDR)&0x0000ffff;  \
+    IDT[(N)].selector = (SELECTOR);           \
+    IDT[(N)].zero = 0;                        \
+    IDT[(N)].type_attr = INTERRUPT_GATE_TYPE; \
+    IDT[(N)].offset_high = ((ADDR)&0xffff0000) >> 16
+
+struct IDT_entry {
+    uint16_t offset_low;
+    uint16_t selector;
+    uint8_t zero;
+    uint8_t type_attr;
+    uint16_t offset_high;
+};
+
+#ifndef _INTERRUPT_C_
+extern struct IDT_entry IDT[256];
+#endif
+
+void init_idt();
+
+// idt_descriptor: uint16_t[3]
+// [0] bit 0 :15 => limit
+// [1] bit 16:47 => address
+extern void asm_load_idt(uint16_t idt_descriptor[3]);
+
+void irq0_handler(void);
+void irq1_handler(void);
+void irq2_handler(void);
+void irq3_handler(void);
+void irq4_handler(void);
+void irq5_handler(void);
+void irq6_handler(void);
+void irq7_handler(void);
+void irq8_handler(void);
+void irq9_handler(void);
+void irq10_handler(void);
+void irq11_handler(void);
+void irq12_handler(void);
+void irq13_handler(void);
+void irq14_handler(void);
+void irq15_handler(void);

+ 126 - 0
src/asm/interrupt.s

@@ -0,0 +1,126 @@
+.code32
+
+.text
+
+.globl irq0
+.type  irq0 @function
+irq0:
+    pushal
+    call irq0_handler
+    popal
+    iret
+
+.globl irq1
+.type  irq1 @function
+irq1:
+    pushal
+    call irq1_handler
+    popal
+    iret
+    
+.globl irq2
+.type  irq2 @function
+irq2:
+    pushal
+    call irq2_handler
+    popal
+    iret
+.globl irq3
+.type  irq3 @function
+irq3:
+    pushal
+    call irq3_handler
+    popal
+    iret
+.globl irq4
+.type  irq4 @function
+irq4:
+    pushal
+    call irq4_handler
+    popal
+    iret
+.globl irq5
+.type  irq5 @function
+irq5:
+    pushal
+    call irq5_handler
+    popal
+    iret
+.globl irq6
+.type  irq6 @function
+irq6:
+    pushal
+    call irq6_handler
+    popal
+    iret
+.globl irq7
+.type  irq7 @function
+irq7:
+    pushal
+    call irq7_handler
+    popal
+    iret
+.globl irq8
+.type  irq8 @function
+irq8:
+    pushal
+    call irq8_handler
+    popal
+    iret
+.globl irq9
+.type  irq9 @function
+irq9:
+    pushal
+    call irq9_handler
+    popal
+    iret
+.globl irq10
+.type  irq10 @function
+irq10:
+    pushal
+    call irq10_handler
+    popal
+    iret
+.globl irq11
+.type  irq11 @function
+irq11:
+    pushal
+    call irq11_handler
+    popal
+    iret
+.globl irq12
+.type  irq12 @function
+irq12:
+    pushal
+    call irq12_handler
+    popal
+    iret
+.globl irq13
+.type  irq13 @function
+irq13:
+    pushal
+    call irq13_handler
+    popal
+    iret
+.globl irq14
+.type  irq14 @function
+irq14:
+    pushal
+    call irq14_handler
+    popal
+    iret
+.globl irq15
+.type  irq15 @function
+irq15:
+    pushal
+    call irq15_handler
+    popal
+    iret
+
+.globl asm_load_idt
+.type  asm_load_idt @function
+asm_load_idt:
+    movl 4(%esp), %edx
+    lidt (%edx)
+    sti
+    ret

+ 15 - 0
src/asm/port_io.s

@@ -0,0 +1,15 @@
+.code32
+
+.text
+
+.globl asm_outb
+.type  asm_outb @function
+asm_outb:
+    pushl %eax
+    pushl %edx
+    movw 12(%esp), %dx
+    movb 16(%esp), %al
+    outb %al, %dx
+    popl %edx
+    popl %eax
+    ret

+ 120 - 0
src/kernel/interrupt.c

@@ -0,0 +1,120 @@
+#define _INTERRUPT_C_
+
+#include <asm/port_io.h>
+#include <kernel/interrupt.h>
+
+static struct IDT_entry IDT[256];
+
+void init_idt()
+{
+    asm_outb(0x20, 0x11); // edge trigger mode
+    asm_outb(0x21, 0x20); // start from int 0x20
+    asm_outb(0x21, 0x04); // PIC1 is connected to IRQ2 (1 << 2)
+    asm_outb(0x21, 0x01); // no buffer mode
+
+    asm_outb(0xa0, 0x11); // edge trigger mode
+    asm_outb(0xa1, 0x28); // start from int 0x28
+    asm_outb(0xa1, 0x02); // connected to IRQ2
+    asm_outb(0xa1, 0x01); // no buffer mode
+
+    // allow all the interrupts
+    asm_outb(0x21, 0x00);
+    asm_outb(0xa1, 0x00);
+
+    // 0x08 stands for kernel code segment
+    SET_UP_IRQ(0, 0x08);
+    SET_UP_IRQ(1, 0x08);
+    SET_UP_IRQ(2, 0x08);
+    SET_UP_IRQ(3, 0x08);
+    SET_UP_IRQ(4, 0x08);
+    SET_UP_IRQ(5, 0x08);
+    SET_UP_IRQ(6, 0x08);
+    SET_UP_IRQ(7, 0x08);
+    SET_UP_IRQ(8, 0x08);
+    SET_UP_IRQ(9, 0x08);
+    SET_UP_IRQ(10, 0x08);
+    SET_UP_IRQ(11, 0x08);
+    SET_UP_IRQ(12, 0x08);
+    SET_UP_IRQ(13, 0x08);
+    SET_UP_IRQ(14, 0x08);
+    SET_UP_IRQ(15, 0x08);
+
+    uint16_t idt_descriptor[3];
+    idt_descriptor[0] = sizeof(struct IDT_entry) * 256;
+    *((uint32_t*)(idt_descriptor + 1)) = (ptr_t)IDT;
+
+    asm_load_idt(idt_descriptor);
+}
+
+void irq0_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq1_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq2_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq3_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq4_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq5_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq6_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq7_handler(void)
+{
+    asm_outb(0x20, 0x20);
+}
+void irq8_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq9_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq10_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq11_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq12_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq13_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq14_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}
+void irq15_handler(void)
+{
+    asm_outb(0xa0, 0x20);
+    asm_outb(0x20, 0x20);
+}

+ 4 - 0
src/kernel_main.c

@@ -1,6 +1,7 @@
 #include <kernel_main.h>
 
 #include <asm/boot.h>
+#include <kernel/interrupt.h>
 #include <kernel/mem.h>
 #include <kernel/stdio.h>
 #include <kernel/vga.h>
@@ -28,6 +29,9 @@ void kernel_main(void)
         (int32_t)asm_mem_size_info.n_64k_blks);
     vga_printk(buf, 0x0fu);
 
+    vga_printk("Initializing interrupt descriptor table...\n", 0x0fu);
+    init_idt();
+
     vga_printk("No work to do, halting...\n", 0x0fU);
 
 _loop: