selectors, descriptors, more interrupt init
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 11 Jun 2021 20:01:32 +0000 (23:01 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 11 Jun 2021 20:01:32 +0000 (23:01 +0300)
sys1/kern/src/desc.c
sys1/kern/src/desc.h
sys1/kern/src/intr.asm
sys1/kern/src/intr.c
sys1/kern/src/intr.h
sys1/kern/src/main.c
sys1/kern/src/mem.asm
sys1/kern/src/mem.c
sys1/kern/src/mem.h

index d02c5fc..9af939e 100644 (file)
 #define SEG_DEF                        0x00400000
 
 
+#define GATE_TYPE_INTR 0x0e00
+#define GATE_TYPE_TRAP 0x0f00
+#define GATE_PRESENT   0x8000
+
+
 void desc_seg(struct desc *desc, int type, uint32_t base, uint32_t limit, int dpl)
 {
        if(type == SEG_NULL) {
@@ -43,3 +48,13 @@ void desc_seg(struct desc *desc, int type, uint32_t base, uint32_t limit, int dp
                break;
        }
 }
+
+
+
+void desc_intr(struct desc *desc, int type, uint16_t sel, uint32_t offs, int dpl)
+{
+       uint32_t gate_type[] = { GATE_TYPE_INTR, GATE_TYPE_TRAP };
+
+       desc->d[0] = (offs & 0xffff) | ((uint32_t)sel << 16);
+       desc->d[1] = (offs & 0xffff0000) | GATE_PRESENT | (dpl << 13) | gate_type[type];
+}
index 9d9f700..e5e723b 100644 (file)
@@ -8,7 +8,9 @@ struct desc {
 };
 
 enum { SEG_NULL, SEG_CODE, SEG_DATA, SEG_TSS };
+enum { GATE_INTR, GATE_TRAP };
 
 void desc_seg(struct desc *desc, int type, uint32_t base, uint32_t limit, int dpl);
+void desc_intr(struct desc *desc, int type, uint16_t sel, uint32_t offs, int dpl);
 
 #endif /* DESC_H_ */
index dd35095..0d73c71 100644 (file)
@@ -4,7 +4,14 @@
        extern intr_handler
 
 PIC1_CMD_PORT  equ 0x20
+PIC1_DATA_PORT equ 0x21
 PIC2_CMD_PORT  equ 0xa0
+PIC2_DATA_PORT equ 0xa1
+
+ICW1_ICW4_NEEDED equ 0x01
+ICW1_INIT      equ 0x10
+ICW4_8086      equ 0x01
+
 OCW2_EOI       equ 0x20
 OCW3_ISR       equ 0x0b
 
@@ -23,6 +30,48 @@ idtlim       dw 0
 idtbase dd 0
 
 
+       global prog_pic
+prog_pic:
+       ; send ICW1 saying we'll follow with ICW4 later
+       mov al, ICW1_INIT | ICW1_ICW4_NEEDED
+       out PIC1_CMD_PORT, al
+       ; send ICW2 with IRQ remapping
+       mov al, [esp + 4]
+       out PIC1_DATA_PORT, al
+       add al, 8
+       out PIC2_DATA_PORT, al
+       ; send ICW3 to setup the master/slave relationship
+       ; ... set bit3 = 3rd interrupt input has a slave
+       mov al, 4
+       out PIC1_DATA_PORT, al
+       ; ... set slave id to 2
+       mov al, 2
+       OUT PIC2_DATA_PORT, al
+       ; send ICW4 to set 8086 mode (no calls generated)
+       mov al, ICW4_8086
+       out PIC1_DATA_PORT, al
+       out PIC2_DATA_PORT, al
+       ; done, reset the data port to 0
+       xor al, al
+       out PIC1_DATA_PORT, al
+       out PIC2_DATA_PORT, al
+       ret
+
+
+       global end_of_irq
+end_of_irq:
+       mov eax, [esp + 4]
+       cmp eax, 8
+       jb .eoi_master
+       ; cascaded IRQ, send EOI to slave PIC first
+       mov al, OCW2_EOI
+       out PIC2_CMD_PORT, al
+.eoi_master: ; send EOI to master PIC
+       mov al, OCW2_EOI
+       out PIC1_CMD_PORT, al
+       ret
+
+
        ; special entry point for IRQ7 to catch and disregard spurious interrupts
        global intr_entry_irq7_verify
 intr_entry_irq7_verify:
@@ -54,12 +103,14 @@ intr_entry_irq15_verify:
 
 
 %macro intr_entry_err 2
+       global intr_entry_%2
 intr_entry_%2:
        push dword %1   ; push interrupt number
        jmp intr_entry_common
 %endmacro
 
 %macro intr_entry_noerr 2
+       global intr_entry_%2
 intr_entry_%2:
        push dword 0    ; push dummy error code
        push dword %1   ; push interrupt number
@@ -89,7 +140,6 @@ intr_entry_common:
        intr_entry_err 12, stack
        intr_entry_err 13, prot
        intr_entry_err 14, page
-       intr_entry_noerr 15, rsvd
        intr_entry_noerr 16, fpu
        intr_entry_err 17, align
        intr_entry_noerr 18, mce
index 5ce0009..dbd8faa 100644 (file)
@@ -1,17 +1,84 @@
+#include <stdio.h>
 #include "intr.h"
 #include "desc.h"
+#include "mem.h"
 
 void set_idt(void *ptr, uint16_t lim);
 
 #define NUM_INTR       256
 static struct desc idt[NUM_INTR] __attribute__((aligned(8)));
+static void (*intr_func[NUM_INTR])();
+
+static struct {
+       char *name;
+       int num;
+       void (*entry)();
+} intrtab[] = {
+       {"divide error", 0, intr_entry_div},
+       {"debug exception", 1, intr_entry_debug},
+       {"non-maskable interrupt", 2, intr_entry_nmi},
+       {"breakpoint", 3, intr_entry_bpt},
+       {"overflow", 4, intr_entry_ovf},
+       {"bounds check", 5, intr_entry_bound},
+       {"invalid opcode", 6, intr_entry_ill},
+       {"missing coprocessor", 7, intr_entry_nodev},
+       {"double fault", 8, intr_entry_dbl},
+       {"coprocessor segment overrun", 9, intr_entry_copseg},
+       {"invalid TSS", 10, intr_entry_tss},
+       {"segment not present", 11, intr_entry_segpres},
+       {"stack exception", 12, intr_entry_stack},
+       {"general protection", 13, intr_entry_prot},
+       {"page fault", 14, intr_entry_page},
+       {"floating point error", 16, intr_entry_fpu},
+       {"alignment check", 17, intr_entry_align},
+       {"machine check", 18, intr_entry_mce},
+       {"SIMD floating point error", 19, intr_entry_sse},
+       {"IRQ 0 (timer)", 32, intr_entry_irq0},
+       {"IRQ 1 (keyboard)", 33, intr_entry_irq1},
+       {"IRQ 2 (cascade)", 34, intr_entry_irq2},
+       {"IRQ 3 (UART 1)", 35, intr_entry_irq3},
+       {"IRQ 4 (UART 0)", 36, intr_entry_irq4},
+       {"IRQ 5", 37, intr_entry_irq5},
+       {"IRQ 6 (floppy)", 38, intr_entry_irq6},
+       {"IRQ 7 (parallel)", 39, intr_entry_irq7_verify},
+       {"IRQ 8 (RTC)", 40, intr_entry_irq8},
+       {"IRQ 9", 41, intr_entry_irq9},
+       {"IRQ 10", 42, intr_entry_irq10},
+       {"IRQ 11", 43, intr_entry_irq11},
+       {"IRQ 12 (PS/2 mouse)", 44, intr_entry_irq12},
+       {"IRQ 13 (coproc)", 45, intr_entry_irq13},
+       {"IRQ 14 (ATA 0)", 46, intr_entry_irq14},
+       {"IRQ 15 (ATA 1)", 47, intr_entry_irq15_verify}
+};
 
 void intr_init(void)
 {
+       int i, inum, type;
+       uint16_t sel_kcode = selector(SEL_KCODE, 0);
+
+       prog_pic(IRQ_OFFS);
+
+       for(i=0; i<256; i++) {
+               type = i < 32 ? GATE_TRAP : GATE_INTR;
+               desc_intr(idt + i, type, sel_kcode, (uint32_t)intr_entry_default, 0);
+       }
+       for(i=0; i<sizeof intrtab / sizeof *intrtab; i++) {
+               inum = intrtab[i].num;
+               type = inum < 32 ? GATE_TRAP : GATE_INTR;
+               desc_intr(idt + inum, type, sel_kcode, (uint32_t)intrtab[i].entry, 0);
+       }
        set_idt(idt, sizeof idt - 1);
 }
 
 void intr_handler(int err, int num)
 {
-}
+       if(intr_func[num]) {
+               intr_func[num]();
+       } else {
+               printf("unhandled interrupt: %d\n", num);
+       }
 
+       if(num >= IRQ_OFFS) {
+               end_of_irq(num - IRQ_OFFS);
+       }
+}
index 10e3fe9..a4e1fde 100644 (file)
@@ -3,6 +3,49 @@
 
 #include "desc.h"
 
+#define IRQ_OFFS               32
+#define IRQ_INTR(x)            ((x) + IRQ_OFFS)
+
 void intr_init(void);
+void prog_pic(int offs);
+void end_of_irq(int irq);
+
+void intr_entry_div();
+void intr_entry_debug();
+void intr_entry_nmi();
+void intr_entry_bpt();
+void intr_entry_ovf();
+void intr_entry_bound();
+void intr_entry_ill();
+void intr_entry_nodev();
+void intr_entry_dbl();
+void intr_entry_copseg();
+void intr_entry_tss();
+void intr_entry_segpres();
+void intr_entry_stack();
+void intr_entry_prot();
+void intr_entry_page();
+void intr_entry_fpu();
+void intr_entry_align();
+void intr_entry_mce();
+void intr_entry_sse();
+void intr_entry_irq0();
+void intr_entry_irq1();
+void intr_entry_irq2();
+void intr_entry_irq3();
+void intr_entry_irq4();
+void intr_entry_irq5();
+void intr_entry_irq6();
+void intr_entry_irq7_verify();
+void intr_entry_irq8();
+void intr_entry_irq9();
+void intr_entry_irq10();
+void intr_entry_irq11();
+void intr_entry_irq12();
+void intr_entry_irq13();
+void intr_entry_irq14();
+void intr_entry_irq15_verify();
+void intr_entry_default();
+
 
 #endif /* INTR_H_ */
index 8426a66..1a84caf 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdint.h>
 #include "vga.h"
 #include "mem.h"
+#include "intr.h"
 
 void drawtext(int x, int y, const char *s)
 {
index 3a4bf85..54c04f3 100644 (file)
@@ -10,8 +10,26 @@ set_gdt:
        lgdt [gdtlim]
        ret
 
+       global setup_selectors
+setup_selectors:
+       ; set data selectors directly
+       mov ax, [esp + 8]
+       mov ss, ax
+       mov es, ax
+       mov ds, ax
+       mov gs, ax
+       mov fs, ax
+       ; set cs with a long jump
+       mov ax, [esp + 4]
+       mov [jseg], ax
+       mov dword [joffs], .setcs
+       jmp far [joffs]
+.setcs: ret
+       
+
        align 4
-       dw 0
+joffs  dd 0
+jseg   dw 0
 gdtlim dw 0
 gdtbase dd 0
 
index 92d6de9..b801a7d 100644 (file)
@@ -3,19 +3,21 @@
 
 void set_gdt(void *addr, uint16_t limit);
 
-enum {
-       SEG_KCODE       = 1,
-       SEG_KDATA       = 2
-};
-
-#define NUM_SEG                3
+#define NUM_SEG        3
 static struct desc gdt[NUM_SEG] __attribute__((aligned(8)));
 
 void mem_init(void)
 {
        desc_seg(gdt, SEG_NULL, 0, 0, 0);
-       desc_seg(gdt + SEG_KCODE, SEG_CODE, 0, 0xffffffff, 0);
-       desc_seg(gdt + SEG_KDATA, SEG_DATA, 0, 0xffffffff, 0);
+       desc_seg(gdt + SEL_KCODE, SEG_CODE, 0, 0xffffffff, 0);
+       desc_seg(gdt + SEL_KDATA, SEG_DATA, 0, 0xffffffff, 0);
 
        set_gdt(gdt, sizeof gdt - 1);
+
+       setup_selectors(selector(SEL_KCODE, 0), selector(SEL_KDATA, 0));
+}
+
+uint16_t selector(int idx, int rpl)
+{
+       return (idx << 3) | (rpl & 3);
 }
index 1517e3e..5e76a6c 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef MEM_H_
 #define MEM_H_
 
+#include <stdint.h>
+
+enum {
+       SEL_KCODE       = 1,
+       SEL_KDATA       = 2
+};
+
 void mem_init(void);
 
+uint16_t selector(int idx, int rpl);
+
+/* defined in mem.asm */
+void setup_selectors(uint16_t code, uint16_t data);
+
 #endif /* MEM_H_ */