From 49efafe1731cc52e6c84f0da9b49772abd0d6510 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Thu, 6 Aug 2020 22:36:39 -0500 Subject: [PATCH] Added code to support getting interrupts from the PIC. Can now get some data from the keyboard, however, it's not quite working yet. --- build_numbers.c | 2 +- includes/idt.h | 2 +- includes/irq.h | 21 +++++++++ includes/kb.h | 7 +++ includes/kernel.h | 1 + includes/pic.h | 7 +++ includes/screen.h | 1 + kernel/idt.c | 67 +++++++++++++++-------------- kernel/interrupt_handler.c | 2 + kernel/interrupt_service_routines.s | 2 +- kernel/irq.s | 67 +++++++++++++++++++++++++++++ kernel/kb.c | 27 ++++++++++++ kernel/kmain.c | 18 ++++++-- kernel/pic.c | 58 +++++++++++++++++++++++++ kernel/screen.c | 35 +++++++++++++++ 15 files changed, 278 insertions(+), 39 deletions(-) create mode 100644 includes/irq.h create mode 100644 includes/kb.h create mode 100644 includes/pic.h create mode 100644 kernel/irq.s create mode 100644 kernel/kb.c create mode 100644 kernel/pic.c diff --git a/build_numbers.c b/build_numbers.c index ffe8d25..7cbc7d7 100644 --- a/build_numbers.c +++ b/build_numbers.c @@ -1,3 +1,3 @@ #ifndef KERNEL_VERSION_NUMBER -#define KERNEL_VERSION_NUMBER "0.0.3-2" +#define KERNEL_VERSION_NUMBER "0.0.3-46" #endif diff --git a/includes/idt.h b/includes/idt.h index 961eefd..5f6d81e 100644 --- a/includes/idt.h +++ b/includes/idt.h @@ -16,6 +16,6 @@ struct idt_ptr } __attribute__((packed)); void install_idt(void); -void idt_set_gate(struct idt_entry*, unsigned long, unsigned short, unsigned char); +void idt_set_gate(unsigned char, unsigned long, unsigned short, unsigned char); void load_idt(struct idt_ptr*); #endif diff --git a/includes/irq.h b/includes/irq.h new file mode 100644 index 0000000..7e043df --- /dev/null +++ b/includes/irq.h @@ -0,0 +1,21 @@ +#ifndef IRQ_H +#define IRQ_H + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +#endif diff --git a/includes/kb.h b/includes/kb.h new file mode 100644 index 0000000..f73ef90 --- /dev/null +++ b/includes/kb.h @@ -0,0 +1,7 @@ +#ifndef KB_H +#define KB_H + +void handle_key_press(void); +void init_kb(void); + +#endif diff --git a/includes/kernel.h b/includes/kernel.h index aa6a518..b52dccb 100644 --- a/includes/kernel.h +++ b/includes/kernel.h @@ -1,4 +1,5 @@ #ifndef KERNEL_H #define KERNEL_H void kmain(); +void kb_c(); #endif diff --git a/includes/pic.h b/includes/pic.h new file mode 100644 index 0000000..f8b2a61 --- /dev/null +++ b/includes/pic.h @@ -0,0 +1,7 @@ +#ifndef PIC_H +#define PIC_H + +void pic_acknowledge(unsigned int); +void setup_pics(void); + +#endif diff --git a/includes/screen.h b/includes/screen.h index 1073529..dddfe0f 100644 --- a/includes/screen.h +++ b/includes/screen.h @@ -4,4 +4,5 @@ void draw_string(char*, unsigned char, unsigned char); int strlen(char*); void clear_screen(void); void print_banner(void); +char* int_to_string(unsigned int, int); #endif diff --git a/kernel/idt.c b/kernel/idt.c index 9a621d4..0058419 100644 --- a/kernel/idt.c +++ b/kernel/idt.c @@ -18,44 +18,45 @@ void idt_install() // For the kernel ring 8E is chosen // 100 for bits 7-5. 1 (present) 00 (the level in this case ring zero) // 01110 for bits 4-0. This is always set to 14. - idt_set_gate(&idt_entries[0], (unsigned int) isr0, 0x08, 0x8E); - idt_set_gate(&idt_entries[1], (unsigned int) isr1, 0x08, 0x8E); - idt_set_gate(&idt_entries[2], (unsigned int) isr2, 0x08, 0x8E); - idt_set_gate(&idt_entries[3], (unsigned int) isr3, 0x08, 0x8E); - idt_set_gate(&idt_entries[4], (unsigned int) isr4, 0x08, 0x8E); - idt_set_gate(&idt_entries[5], (unsigned int) isr5, 0x08, 0x8E); - idt_set_gate(&idt_entries[6], (unsigned int) isr6, 0x08, 0x8E); - idt_set_gate(&idt_entries[7], (unsigned int) isr7, 0x08, 0x8E); - idt_set_gate(&idt_entries[8], (unsigned int) isr8, 0x08, 0x8E); - idt_set_gate(&idt_entries[9], (unsigned int) isr9, 0x08, 0x8E); - idt_set_gate(&idt_entries[10], (unsigned int) isr10, 0x08, 0x8E); - idt_set_gate(&idt_entries[11], (unsigned int) isr11, 0x08, 0x8E); - idt_set_gate(&idt_entries[12], (unsigned int) isr12, 0x08, 0x8E); - idt_set_gate(&idt_entries[13], (unsigned int) isr13, 0x08, 0x8E); - idt_set_gate(&idt_entries[14], (unsigned int) isr14, 0x08, 0x8E); - idt_set_gate(&idt_entries[15], (unsigned int) isr15, 0x08, 0x8E); - idt_set_gate(&idt_entries[16], (unsigned int) isr16, 0x08, 0x8E); - idt_set_gate(&idt_entries[17], (unsigned int) isr17, 0x08, 0x8E); - idt_set_gate(&idt_entries[18], (unsigned int) isr18, 0x08, 0x8E); - idt_set_gate(&idt_entries[19], (unsigned int) isr19, 0x08, 0x8E); - idt_set_gate(&idt_entries[20], (unsigned int) isr20, 0x08, 0x8E); - idt_set_gate(&idt_entries[21], (unsigned int) isr21, 0x08, 0x8E); - idt_set_gate(&idt_entries[22], (unsigned int) isr22, 0x08, 0x8E); - idt_set_gate(&idt_entries[23], (unsigned int) isr23, 0x08, 0x8E); - idt_set_gate(&idt_entries[24], (unsigned int) isr24, 0x08, 0x8E); - idt_set_gate(&idt_entries[25], (unsigned int) isr25, 0x08, 0x8E); - idt_set_gate(&idt_entries[26], (unsigned int) isr26, 0x08, 0x8E); - idt_set_gate(&idt_entries[27], (unsigned int) isr27, 0x08, 0x8E); - idt_set_gate(&idt_entries[28], (unsigned int) isr28, 0x08, 0x8E); - idt_set_gate(&idt_entries[29], (unsigned int) isr29, 0x08, 0x8E); - idt_set_gate(&idt_entries[30], (unsigned int) isr30, 0x08, 0x8E); - idt_set_gate(&idt_entries[31], (unsigned int) isr31, 0x08, 0x8E); + idt_set_gate(0, (unsigned int) isr0, 0x08, 0x8E); + idt_set_gate(1, (unsigned int) isr1, 0x08, 0x8E); + idt_set_gate(2, (unsigned int) isr2, 0x08, 0x8E); + idt_set_gate(3, (unsigned int) isr3, 0x08, 0x8E); + idt_set_gate(4, (unsigned int) isr4, 0x08, 0x8E); + idt_set_gate(5, (unsigned int) isr5, 0x08, 0x8E); + idt_set_gate(6, (unsigned int) isr6, 0x08, 0x8E); + idt_set_gate(7, (unsigned int) isr7, 0x08, 0x8E); + idt_set_gate(8, (unsigned int) isr8, 0x08, 0x8E); + idt_set_gate(9, (unsigned int) isr9, 0x08, 0x8E); + idt_set_gate(10, (unsigned int) isr10, 0x08, 0x8E); + idt_set_gate(11, (unsigned int) isr11, 0x08, 0x8E); + idt_set_gate(12, (unsigned int) isr12, 0x08, 0x8E); + idt_set_gate(13, (unsigned int) isr13, 0x08, 0x8E); + idt_set_gate(14, (unsigned int) isr14, 0x08, 0x8E); + idt_set_gate(15, (unsigned int) isr15, 0x08, 0x8E); + idt_set_gate(16, (unsigned int) isr16, 0x08, 0x8E); + idt_set_gate(17, (unsigned int) isr17, 0x08, 0x8E); + idt_set_gate(18, (unsigned int) isr18, 0x08, 0x8E); + idt_set_gate(19, (unsigned int) isr19, 0x08, 0x8E); + idt_set_gate(20, (unsigned int) isr20, 0x08, 0x8E); + idt_set_gate(21, (unsigned int) isr21, 0x08, 0x8E); + idt_set_gate(22, (unsigned int) isr22, 0x08, 0x8E); + idt_set_gate(23, (unsigned int) isr23, 0x08, 0x8E); + idt_set_gate(24, (unsigned int) isr24, 0x08, 0x8E); + idt_set_gate(25, (unsigned int) isr25, 0x08, 0x8E); + idt_set_gate(26, (unsigned int) isr26, 0x08, 0x8E); + idt_set_gate(27, (unsigned int) isr27, 0x08, 0x8E); + idt_set_gate(28, (unsigned int) isr28, 0x08, 0x8E); + idt_set_gate(29, (unsigned int) isr29, 0x08, 0x8E); + idt_set_gate(30, (unsigned int) isr30, 0x08, 0x8E); + idt_set_gate(31, (unsigned int) isr31, 0x08, 0x8E); load_idt(&idt); } -void idt_set_gate(struct idt_entry* entry, unsigned long base, unsigned short sel, unsigned char flags) +void idt_set_gate(unsigned char index, unsigned long base, unsigned short sel, unsigned char flags) { + struct idt_entry* entry = &idt.idt_entries_start[index]; entry->base_lo = (base & 0xFFFF); entry->base_hi = (base >> 16) & 0xFFFF; diff --git a/kernel/interrupt_handler.c b/kernel/interrupt_handler.c index df74742..2143b8b 100644 --- a/kernel/interrupt_handler.c +++ b/kernel/interrupt_handler.c @@ -1,8 +1,10 @@ #include "../includes/interrupt_handler.h" #include "../includes/serial.h" +#include "../includes/screen.h" void interrupt_handler(struct isr_state stack) { + write_to_com(COM1_PORT, int_to_string(stack.int_no, 10)); write_to_com(COM1_PORT, "Divide by zero detected!\n"); write_to_com(COM1_PORT, "Halting system!\n"); asm("cli"); diff --git a/kernel/interrupt_service_routines.s b/kernel/interrupt_service_routines.s index 68df897..910977d 100644 --- a/kernel/interrupt_service_routines.s +++ b/kernel/interrupt_service_routines.s @@ -29,7 +29,7 @@ global isr27 global isr28 global isr29 global isr30 -global isr31 ; reserved +global isr31 ; Reserved isr0: ; division by zero cli diff --git a/kernel/irq.s b/kernel/irq.s new file mode 100644 index 0000000..b5784bb --- /dev/null +++ b/kernel/irq.s @@ -0,0 +1,67 @@ +global irq0 ; PIC Timer Interrupt +global irq1 ; Keyboard +global irq2 ; Cascade (Used internally by the two PICs; never raised) +global irq3 ; COM2 +global irq4 ; COM1 +global irq5 ; LPT2 +global irq6 ; Floppy Disk +global irq7 ; LPT1 +global irq8 ; CMOS realt-time clock +global irq9 ; Free for perpherals / legacy SCSI / NIC +global irq10 ; Free for perpherals / NIC +global irq11 ; Free for perpherals / NIC +global irq12 ; PS2 mouse +global irq13 ; FPU / Coprocessor / Inter-process +global irq14 ; Primary ATA HDD +global irq15 ; Secondary ATA HDD + +extern handle_key_press + +irq0: + iret + +irq1: + call handle_key_press + iret + +irq2: + iret + +irq3: + iret + +irq4: + iret + +irq5: + iret + +irq6: + iret + +irq7: + iret + +irq8: + iret + +irq9: + iret + +irq10: + iret + +irq11: + iret + +irq12: + iret + +irq13: + iret + +irq14: + iret + +irq15: + iret diff --git a/kernel/kb.c b/kernel/kb.c new file mode 100644 index 0000000..f7025ae --- /dev/null +++ b/kernel/kb.c @@ -0,0 +1,27 @@ +#include "../includes/kb.h" +#include "../includes/pic.h" +#include "../includes/screen.h" + +#define KB_PORT 0x60 +#define KB_STATUS_PORT 0x64 + +void handle_key_press() +{ + pic_acknowledge(33); + + unsigned char status = inb(KB_STATUS_PORT); + + if(status & 0x01) + { + char keycode = inb(KB_PORT); + + if(keycode < 0) return; + + draw_string(int_to_string(keycode, 10), 0xF, 0x0); + } +} + +void init_kb() +{ + outb(0x21, 0xFD); +} diff --git a/kernel/kmain.c b/kernel/kmain.c index fa9a09e..bbfb46c 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -4,6 +4,8 @@ #include "../includes/serial.h" #include "../includes/screen.h" #include "../includes/loader.h" +#include "../includes/pic.h" +#include "../includes/kb.h" struct multiboot_header header __attribute((section(".multiboot"))) = (struct multiboot_header) {.magic = 0x1BADB002, .flags = 0x1, .checksum = -464367619}; @@ -26,9 +28,14 @@ void kmain() print_message("Installing IDT...\n", 0xF, 0x0); idt_install(); print_message("IDT installed.\n", 0xF, 0x0); - - int i = 5 / 0; - asm("hlt"); + //asm("xchg %bx, %bx"); // Boch's break point + setup_pics(); + //kb + init_kb(); + //asm("xchg %bx, %bx"); + asm("sti"); + //for(;;); + idle(); } void print_message(unsigned char* msg, unsigned char fg, unsigned char bg) @@ -36,3 +43,8 @@ void print_message(unsigned char* msg, unsigned char fg, unsigned char bg) write_to_com(COM1_PORT, msg); draw_string(msg, fg, bg); } + +void idle() +{ + for(;;) asm("hlt"); +} diff --git a/kernel/pic.c b/kernel/pic.c new file mode 100644 index 0000000..ba466e3 --- /dev/null +++ b/kernel/pic.c @@ -0,0 +1,58 @@ +#include "../includes/pic.h" +#include "../includes/io.h" +#include "../includes/idt.h" +#include "../includes/irq.h" + +#define PIC1_PORT 0x20 +#define PIC1_DATA_PORT 0X21 +#define PIC2_PORT 0xA0 +#define PIC2_DATA_PORT 0XA1 + +#define PIC1_START_INTERRUPT 0x20 +#define PIC2_START_INTERRUPT 0x28 +#define PIC2_END_INTERRUPT PIC2_START_INTERRUPT + 7 + +#define PIC_ACK 0x20 + +void pic_acknowledge(unsigned int interrupt_no) +{ + if (interrupt_no < PIC2_START_INTERRUPT) + outb(PIC1_PORT, PIC_ACK); + else + outb(PIC2_PORT, PIC_ACK); +} + +void setup_pics(void) +{ + // The PIC uses Initialization Command Words (ICW) to communicate. + // So we start with the first ICW, 0x11, this tells the PIC to expect + // 3 more ICWs. + outb(PIC1_PORT, 0x11); + outb(PIC2_PORT, 0x11); + + // This tells the pic what offset to use when it generates the interrupt numbers. + // Since the first 32 ISRs are reserved by the CPU we must start at IRS32 and work + // our way up. When the PIC recieves an interrupt on it's input line, it will add + // the supplied values to that number before sending the newly made number to the CPU. + // Thereby remapping an interrupt number that would have normally conflicted with the + // values in the IDT. + outb(PIC1_DATA_PORT, PIC1_START_INTERRUPT); + outb(PIC2_DATA_PORT, PIC2_START_INTERRUPT); + + // This ICW allows for cascading of their outputs to inputs between each other. + // I'm not sure what that really means but at this current time I'm not going to + // be doing this, so the bits will all be set to zero. + outb(PIC1_DATA_PORT, 0x00); + outb(PIC2_DATA_PORT, 0x00); + + // This is the environment info, and setting the lowest bit tells the PICs + // that we're running in 80x86 mode. + outb(PIC1_DATA_PORT, 0x01); + outb(PIC2_DATA_PORT, 0x01); + + // Finally, we have the interrupt masks. + outb(PIC1_DATA_PORT, 0xFF); + outb(PIC2_DATA_PORT, 0xFF); + + idt_set_gate(33, (unsigned long) &irq1, 0x08, 0x8E); +} diff --git a/kernel/screen.c b/kernel/screen.c index c25f532..0b8a522 100644 --- a/kernel/screen.c +++ b/kernel/screen.c @@ -119,3 +119,38 @@ int strlen(char* string) return len; } + +//Code reference: +//http://www.strudel.org.uk/itoa/ +char* int_to_string(unsigned int value, int base) +{ + static char buf[32] = {0}; + //void* ptr = Malloc(32); + //if(ptr == 0) + //{ + //puts("Malloc failed to allocate!\n"); + //return ""; + //} + + //char buf = (char*) ptr; + + if(value == 0) + { + buf[0] = '0'; + //*buf++ = '0'; + //return buf; + return &buf[0]; + } + + int i = 30; + + for(; value && i; --i, value /= base) + { + //*buf++ = "0123456789ABCDEF"[value % base]; + buf[i] = "0123456789ABCDEF"[value % base]; + } + + //Free(ptr); + //return buf; + return &buf[i+1]; +}