From 578d467b80015c52d0c96c8443b4c13936f33365 Mon Sep 17 00:00:00 2001 From: Aleksa Vučković Date: Mon, 11 Oct 2021 11:35:59 +0200 Subject: (IDT + keyboard) finally working --- src/boot.s | 57 +++++++++++++++++++++++++------ src/gdt.c | 13 ++++---- src/idt.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/kernel.c | 86 +++++++++++++++++++++++++++++++++++++---------- src/keyboard.h | 74 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 300 insertions(+), 33 deletions(-) create mode 100644 src/idt.c create mode 100644 src/keyboard.h (limited to 'src') diff --git a/src/boot.s b/src/boot.s index a0f0c2e..b88e8f7 100644 --- a/src/boot.s +++ b/src/boot.s @@ -12,33 +12,70 @@ .global _start .global load_gdt +.global load_idt +.global enable_interrupts +.global keyboard_handler +.global ioport_in +.global ioport_out + +.extern init_gdt_table +.extern handle_keyboard_interrupt +.extern kernel_main load_gdt: movl 4(%esp), %edx lgdt (%edx) ret +load_idt: + movl 4(%esp), %edx + lidt (%edx) + sti + ret + +keyboard_handler: + pushal + cld + call handle_keyboard_interrupt + popal + iretl + +ioport_in: + movl 4(%esp),%edx + in %dx,%al + ret + +ioport_out: + movl 4(%esp),%edx + movl 8(%esp),%eax + outb %al,%dx + ret + +.set CODE_SEGMENT, 0x08 +.set DATA_SEGMENT, 0x10 + .section .bss .align 16 stack_bottom: -.skip 16384 # 16 KiB +.skip 16384 stack_top: .section .text .type _start, @function _start: call init_gdt_table - mov 0x10, %ax - mov %ds, %ax - mov %es, %ax - mov %fs, %ax - mov %gs, %ax - mov %ss, %ax - mov $stack_top, %esp + ljmp $CODE_SEGMENT, $next + next: + movw $DATA_SEGMENT, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + movl $stack_top, %esp cli call _init call kernel_main -1: hlt - jmp 1b + hlt .size _start, . - _start diff --git a/src/gdt.c b/src/gdt.c index 9f87032..554c2ee 100644 --- a/src/gdt.c +++ b/src/gdt.c @@ -24,13 +24,14 @@ extern void load_gdt(struct gdt_pointer *gdtp); struct gdt_entry gdt[3]; struct gdt_pointer gdtp; -void init_gdt_entry(size_t num, uint32_t limit, uint32_t base1, uint32_t base2, uint8_t access, uint8_t limit_flags, uint8_t base3) +void init_gdt_entry(size_t num, uint32_t limit, uint32_t base, uint8_t access, uint8_t limit_flags) { gdt[num].limit=limit; - gdt[num].base1=base1; + gdt[num].base1=(base & 0xffff); + gdt[num].base2=(base & 0xff0000) >> 16; gdt[num].access=access; gdt[num].limit_flags=limit_flags; - gdt[num].base3=base3; + gdt[num].base3=(base & 0xff000000) >> 24; } void init_gdt_table() @@ -39,11 +40,11 @@ void init_gdt_table() gdtp.offset=(uint32_t)&gdt; //null - init_gdt_entry(0,0,0,0,0,0,0); + init_gdt_entry(0,0,0,0,0); //code - init_gdt_entry(1,0xffff,0x0000,0x00,0b10011010,0b11001111,0x00); + init_gdt_entry(1,0xffffffff,0,0b10011010,0b11001111); //data - init_gdt_entry(2,0xffff,0x0000,0x00,0b10010010,0b11001111,0x00); + init_gdt_entry(2,0xffffffff,0,0b10010010,0b11001111); load_gdt(&gdtp); } diff --git a/src/idt.c b/src/idt.c new file mode 100644 index 0000000..479d397 --- /dev/null +++ b/src/idt.c @@ -0,0 +1,103 @@ +#include +#include +#include + +#define INTERRUPT_GATE_32 0x8e + +#define KERNEL_CODE 0x08 +#define KERNEL_DATA 0x10 + +#define PIC1_COMMAND_PORT 0x20 +#define PIC1_DATA_PORT 0x21 +#define PIC2_COMMAND_PORT 0xA0 +#define PIC2_DATA_PORT 0xA1 + +struct idt_entry +{ + uint16_t offset1; + uint16_t selector; + uint8_t zero; + uint8_t type_attr; + uint16_t offset2; +} __attribute__((packed)); + +struct idt_pointer +{ + uint16_t size; + uint32_t offset; +} __attribute__((packed)); + +// asm function +extern void load_idt(struct idt_pointer *idtp); +extern void keyboard_handler(); +extern void ioport_out(uint8_t port, char data); + +struct idt_entry idt[256]; +struct idt_pointer idtp; + +void init_idt_entry(size_t num, uint32_t offset, uint16_t selector, uint8_t type_attr) +{ + idt[num].offset1=(offset & 0xffff); + idt[num].selector=selector; + idt[num].zero=0; + idt[num].type_attr=type_attr; + idt[num].offset2=(offset & 0xffff0000)>>16; +} + +void init_idt_table() +{ + // Program the PICs - Programmable Interrupt Controllers + // Background: + // In modern architectures, the PIC is not a separate chip. + // It is emulated in the CPU for backwards compatability. + // The APIC (Advanced Programmable Interrupt Controller) + // is the new version of the PIC that is integrated into the CPU. + // Default vector offset for PIC is 8 + // This maps IRQ0 to interrupt 8, IRQ1 to interrupt 9, etc. + // This is a problem. The CPU reserves the first 32 interrupts for + // CPU exceptions such as divide by 0, etc. + // In programming the PICs, we move this offset to 0x2 (32) so that + // we can handle all interrupts coming to the PICs without overlapping + // with any CPU exceptions. + + // Send ICWs - Initialization Command Words + // PIC1: IO Port 0x20 (command), 0xA0 (data) + // PIC2: IO Port 0x21 (command), 0xA1 (data) + // ICW1: Initialization command + // Send a fixed value of 0x11 to each PIC to tell it to expect ICW2-4 + // Restart PIC1 + ioport_out(PIC1_COMMAND_PORT, 0x11); + ioport_out(PIC2_COMMAND_PORT, 0x11); + // ICW2: Vector Offset (this is what we are fixing) + // Start PIC1 at 32 (0x20 in hex) (IRQ0=0x20, ..., IRQ7=0x27) + // Start PIC2 right after, at 40 (0x28 in hex) + ioport_out(PIC1_DATA_PORT, 0x20); + ioport_out(PIC2_DATA_PORT, 0x28); + // ICW3: Cascading (how master/slave PICs are wired/daisy chained) + // Tell PIC1 there is a slave PIC at IRQ2 (why 4? don't ask me - https://wiki.osdev.org/8259_PIC) + // Tell PIC2 "its cascade identity" - again, I'm shaky on this concept. More resources in notes + ioport_out(PIC1_DATA_PORT, 0x0); + ioport_out(PIC2_DATA_PORT, 0x0); + // ICW4: "Gives additional information about the environemnt" + // See notes for some potential values + // We are using 8086/8088 (MCS-80/85) mode + // Not sure if that's relevant, but there it is. + // Other modes appear to be special slave/master configurations (see wiki) + ioport_out(PIC1_DATA_PORT, 0x1); + ioport_out(PIC2_DATA_PORT, 0x1); + // Voila! PICs are initialized + + // Mask all interrupts (why? not entirely sure) + // 0xff is 16 bits that are all 1. + // This masks each of the 16 interrupts for that PIC. + ioport_out(PIC1_DATA_PORT, 0xff); + ioport_out(PIC2_DATA_PORT, 0xff); + + init_idt_entry(0x21,(uint32_t)keyboard_handler,KERNEL_CODE,INTERRUPT_GATE_32); + + idtp.size=sizeof(struct idt_entry)*256-1; + idtp.offset=(uint32_t)&idt; + + + load_idt(&idtp); +} diff --git a/src/kernel.c b/src/kernel.c index c6d1045..0882580 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -6,6 +6,17 @@ static const size_t VGA_WIDTH = 80; static const size_t VGA_HEIGHT = 25; +#define PIC1_COMMAND_PORT 0x20 +#define PIC1_DATA_PORT 0x21 +#define PIC2_COMMAND_PORT 0xA0 +#define PIC2_DATA_PORT 0xA1 +// IO Ports for Keyboard +#define KEYBOARD_DATA_PORT 0x60 +#define KEYBOARD_STATUS_PORT 0x64 + +extern char ioport_in(uint8_t port); +extern void ioport_out(uint8_t port, char data); + static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) { return fg | bg << 4; @@ -23,24 +34,24 @@ uint16_t* terminal_buffer; void terminal_initialize(void) { - terminal_row = 0; - terminal_column = 0; - terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); - terminal_buffer = (uint16_t*) 0xB8000; - for (size_t y = 0; y < VGA_HEIGHT; y++) + terminal_row=0; + terminal_column=0; + terminal_color=vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + terminal_buffer=(uint16_t*) 0xB8000; + for(size_t y=0;y= 128) return; + + if(keycode==14) + { + if(terminal_column) terminal_column--; + terminal_putchar(keyboard[keycode]); + terminal_column--; + return; + } - for(size_t i=0;i<50;i++) - { + terminal_putchar(keyboard[keycode]); + + } +} +void print_message() +{ + for(size_t i=0;i<50;i++) + { for(size_t j=0;j