diff options
author | Marvin Borner | 2020-08-09 16:51:01 +0200 |
---|---|---|
committer | Marvin Borner | 2020-08-09 16:51:01 +0200 |
commit | 162d024a53e1e31e00ff0b6f47dd4590edebc551 (patch) | |
tree | 711d3886c300dfaddffdafaa89b690b45eb2101d /kernel/drivers | |
parent | 79f2fa136f26a0b87917336e089485712ee49bd6 (diff) |
Heavy restructuring of libc, kernel and apps
Diffstat (limited to 'kernel/drivers')
-rw-r--r-- | kernel/drivers/cpu.c | 69 | ||||
-rw-r--r-- | kernel/drivers/ide.c | 41 | ||||
-rw-r--r-- | kernel/drivers/interrupts.asm | 142 | ||||
-rw-r--r-- | kernel/drivers/interrupts.c | 231 | ||||
-rw-r--r-- | kernel/drivers/keyboard.c | 68 | ||||
-rw-r--r-- | kernel/drivers/serial.c | 32 | ||||
-rw-r--r-- | kernel/drivers/timer.c | 39 | ||||
-rw-r--r-- | kernel/drivers/vesa.c | 40 |
8 files changed, 662 insertions, 0 deletions
diff --git a/kernel/drivers/cpu.c b/kernel/drivers/cpu.c new file mode 100644 index 0000000..5c27c51 --- /dev/null +++ b/kernel/drivers/cpu.c @@ -0,0 +1,69 @@ +// MIT License, Copyright (c) 2020 Marvin Borner +// This file is a wrapper around some CPU asm calls + +#include <def.h> + +u8 inb(u16 port) +{ + u8 value; + __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +u16 inw(u16 port) +{ + u16 value; + __asm__ volatile("inw %1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +u32 inl(u16 port) +{ + u32 value; + __asm__ volatile("inl %1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +void insl(u16 port, void *addr, int n) +{ + __asm__ volatile("cld; rep insl" + : "=D"(addr), "=c"(n) + : "d"(port), "0"(addr), "1"(n) + : "memory", "cc"); +} + +void outb(u16 port, u8 data) +{ + __asm__ volatile("outb %0, %1" ::"a"(data), "Nd"(port)); +} + +void outw(u16 port, u16 data) +{ + __asm__ volatile("outw %0, %1" ::"a"(data), "Nd"(port)); +} + +void outl(u16 port, u32 data) +{ + __asm__ volatile("outl %0, %1" ::"a"(data), "Nd"(port)); +} + +void cli() +{ + __asm__ volatile("cli"); +} + +void sti() +{ + __asm__ volatile("sti"); +} + +void hlt() +{ + __asm__ volatile("hlt"); +} + +void idle() +{ + while (1) + hlt(); +} diff --git a/kernel/drivers/ide.c b/kernel/drivers/ide.c new file mode 100644 index 0000000..fe3955c --- /dev/null +++ b/kernel/drivers/ide.c @@ -0,0 +1,41 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#include <cpu.h> +#include <def.h> +#include <ide.h> + +int ide_wait(int check) +{ + char r; + + // Wait while drive is busy. Once just ready is set, exit the loop + while (((r = (char)inb(IDE_IO | IDE_CMD)) & (IDE_BUSY | IDE_READY)) != IDE_READY) + ; + + // Check for errors + if (check && (r & (IDE_DRIVE_FAULT | IDE_ERROR)) != 0) + return 0xF; + return 0; +} + +void *ide_read(void *b, u32 block) +{ + int sector_per_block = BLOCK_SIZE / SECTOR_SIZE; // 2 + int sector = block * sector_per_block; + + ide_wait(0); + outb(IDE_IO | IDE_SECTOR_COUNT, sector_per_block); // Number of sectors + outb(IDE_IO | IDE_LOW, LBA_LOW(sector)); + outb(IDE_IO | IDE_MID, LBA_MID(sector)); + outb(IDE_IO | IDE_HIGH, LBA_HIGH(sector)); + + // Slave/Master << 4 and last 4 bits + outb(IDE_IO | IDE_HEAD, 0xE0 | (1 << 4) | LBA_LAST(sector)); + outb(IDE_IO | IDE_CMD, IDE_CMD_READ); + ide_wait(0); + + // Read-only + insl(IDE_IO, b, BLOCK_SIZE / 4); + + return b; +} diff --git a/kernel/drivers/interrupts.asm b/kernel/drivers/interrupts.asm new file mode 100644 index 0000000..59c323c --- /dev/null +++ b/kernel/drivers/interrupts.asm @@ -0,0 +1,142 @@ +; MIT License, Copyright (c) 2020 Marvin Borner + +; IRQ + +%macro IRQ 2 + global irq%1 + irq%1: + cli + push byte 0 + push byte %2 + jmp irq_common_stub +%endmacro + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +extern irq_handler +irq_common_stub: + pusha + + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + cld + + push esp + call irq_handler + add esp, 4 + + pop gs + pop fs + pop es + pop ds + popa + + add esp, 8 + sti + iret + +; ISR + +%macro ISR_NOERRCODE 1 + global isr%1 + isr%1: + cli + push byte 0 + push %1 + jmp isr_common_stub +%endmacro + +%macro ISR_ERRCODE 1 + global isr%1 + isr%1: + cli + push byte %1 + jmp isr_common_stub +%endmacro + +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_NOERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_NOERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 +ISR_NOERRCODE 128 + +extern isr_handler +isr_common_stub: + pusha + + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + cld + + push esp + call isr_handler + add esp, 4 + + pop gs + pop fs + pop es + pop ds + popa + + add esp, 8 + sti + iret diff --git a/kernel/drivers/interrupts.c b/kernel/drivers/interrupts.c new file mode 100644 index 0000000..0b94208 --- /dev/null +++ b/kernel/drivers/interrupts.c @@ -0,0 +1,231 @@ +// MIT License, Copyright (c) 2020 Marvin Borner +// TODO: Remove some magic numbers + +#include <cpu.h> +#include <def.h> +#include <interrupts.h> +#include <mem.h> +#include <print.h> +#include <serial.h> + +/** + * IDT + */ + +void idt_set_gate(u8 num, u32 base, u16 sel, u8 flags) +{ + // Specify the interrupt routine's base address + idt[num].base_low = (u16)(base & 0xFFFF); + idt[num].base_high = (u16)((base >> 16) & 0xFFFF); + + // Set selector/segment of IDT entry + idt[num].sel = sel; + idt[num].always0 = 0; + idt[num].flags = (u8)(flags | 0x60); +} + +// Install IDT +void idt_install() +{ + // Set IDT pointer and limit + idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1; + idt_ptr.base = &idt; + + // Clear IDT by setting memory cells to 0 + memset(&idt, 0, sizeof(struct idt_entry) * 256); + + __asm__("lidt %0" : : "m"(idt_ptr)); +} + +/** + * IRQ + */ + +void (*irq_routines[16])(struct regs *) = { 0 }; + +// Install IRQ handler +void irq_install_handler(int irq, void (*handler)(struct regs *r)) +{ + irq_routines[irq] = handler; +} + +// Remove IRQ handler +void irq_uninstall_handler(int irq) +{ + irq_routines[irq] = 0; +} + +// Remap the IRQ table +void irq_remap() +{ + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, 0x20); + outb(0xA1, 0x28); + outb(0x21, 0x04); + outb(0xA1, 0x02); + outb(0x21, 0x01); + outb(0xA1, 0x01); + outb(0x21, 0x00); + outb(0xA1, 0x00); +} + +// Handle IRQ ISRs +void irq_handler(struct regs *r) +{ + void (*handler)(struct regs * r); + + // Execute custom handler if exists + handler = irq_routines[r->int_no - 32]; + if (handler) + handler(r); + + // Send EOI to second (slave) PIC + if (r->int_no >= 40) + outb(0xA0, 0x20); + + // Send EOI to master PIC + outb(0x20, 0x20); +} + +// Map ISRs to the correct entries in the IDT +void irq_install() +{ + irq_remap(); + + idt_set_gate(32, (u32)irq0, 0x08, 0x8E); + idt_set_gate(33, (u32)irq1, 0x08, 0x8E); + idt_set_gate(34, (u32)irq2, 0x08, 0x8E); + idt_set_gate(35, (u32)irq3, 0x08, 0x8E); + idt_set_gate(36, (u32)irq4, 0x08, 0x8E); + idt_set_gate(37, (u32)irq5, 0x08, 0x8E); + idt_set_gate(38, (u32)irq6, 0x08, 0x8E); + idt_set_gate(39, (u32)irq7, 0x08, 0x8E); + + idt_set_gate(40, (u32)irq8, 0x08, 0x8E); + idt_set_gate(41, (u32)irq9, 0x08, 0x8E); + idt_set_gate(42, (u32)irq10, 0x08, 0x8E); + idt_set_gate(43, (u32)irq11, 0x08, 0x8E); + idt_set_gate(44, (u32)irq12, 0x08, 0x8E); + idt_set_gate(45, (u32)irq13, 0x08, 0x8E); + idt_set_gate(46, (u32)irq14, 0x08, 0x8E); + idt_set_gate(47, (u32)irq15, 0x08, 0x8E); +} + +/** + * ISR + */ + +void (*isr_routines[256])(struct regs *) = { 0 }; + +const char *isr_exceptions[32] = { "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" }; + +void isr_install_handler(int isr, void (*handler)(struct regs *r)) +{ + isr_routines[isr] = handler; +} + +void isr_uninstall_handler(int isr) +{ + isr_routines[isr] = 0; +} + +void isr_handler(struct regs *r) +{ + void (*handler)(struct regs * r); + + // Execute fault handler if exists + handler = isr_routines[r->int_no]; + if (handler) { + handler(r); + } else if (r->int_no <= 32) { + cli(); + printf("\n%s Exception, halting!\n", isr_exceptions[r->int_no]); + printf("Error code: %d\n", r->err_code); + while (1) { + }; + } +} + +void isr_install() +{ + idt_set_gate(0, (u32)isr0, 0x08, 0x8E); + idt_set_gate(1, (u32)isr1, 0x08, 0x8E); + idt_set_gate(2, (u32)isr2, 0x08, 0x8E); + idt_set_gate(3, (u32)isr3, 0x08, 0x8E); + idt_set_gate(4, (u32)isr4, 0x08, 0x8E); + idt_set_gate(5, (u32)isr5, 0x08, 0x8E); + idt_set_gate(6, (u32)isr6, 0x08, 0x8E); + idt_set_gate(7, (u32)isr7, 0x08, 0x8E); + + idt_set_gate(8, (u32)isr8, 0x08, 0x8E); + idt_set_gate(9, (u32)isr9, 0x08, 0x8E); + idt_set_gate(10, (u32)isr10, 0x08, 0x8E); + idt_set_gate(11, (u32)isr11, 0x08, 0x8E); + idt_set_gate(12, (u32)isr12, 0x08, 0x8E); + idt_set_gate(13, (u32)isr13, 0x08, 0x8E); + idt_set_gate(14, (u32)isr14, 0x08, 0x8E); + idt_set_gate(15, (u32)isr15, 0x08, 0x8E); + + idt_set_gate(16, (u32)isr16, 0x08, 0x8E); + idt_set_gate(17, (u32)isr17, 0x08, 0x8E); + idt_set_gate(18, (u32)isr18, 0x08, 0x8E); + idt_set_gate(19, (u32)isr19, 0x08, 0x8E); + idt_set_gate(20, (u32)isr20, 0x08, 0x8E); + idt_set_gate(21, (u32)isr21, 0x08, 0x8E); + idt_set_gate(22, (u32)isr22, 0x08, 0x8E); + idt_set_gate(23, (u32)isr23, 0x08, 0x8E); + + idt_set_gate(24, (u32)isr24, 0x08, 0x8E); + idt_set_gate(25, (u32)isr25, 0x08, 0x8E); + idt_set_gate(26, (u32)isr26, 0x08, 0x8E); + idt_set_gate(27, (u32)isr27, 0x08, 0x8E); + idt_set_gate(28, (u32)isr28, 0x08, 0x8E); + idt_set_gate(29, (u32)isr29, 0x08, 0x8E); + idt_set_gate(30, (u32)isr30, 0x08, 0x8E); + idt_set_gate(31, (u32)isr31, 0x08, 0x8E); +} + +/** + * Combined + */ +void interrupts_install() +{ + idt_install(); + isr_install(); + irq_install(); +} diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c new file mode 100644 index 0000000..38ff1f7 --- /dev/null +++ b/kernel/drivers/keyboard.c @@ -0,0 +1,68 @@ +#include <cpu.h> +#include <def.h> +#include <gui.h> +#include <interrupts.h> + +char keymap[128]; + +// TODO: Use keyboard as event and move logic to other file +void keyboard_handler() +{ + u8 scan_code = inb(0x60); + + if (scan_code > 128) + return; + + if ((scan_code & 0x80) == 0) { // PRESS + gui_term_write_char(keymap[scan_code]); + } +} + +void keyboard_acknowledge() +{ + while (inb(0x60) != 0xfa) + ; +} + +void keyboard_rate() +{ + outb(0x60, 0xF3); + keyboard_acknowledge(); + outb(0x60, 0x0); // Rate{00000} Delay{00} 0 +} + +void keyboard_install() +{ + //keyboard_rate(); TODO: Fix keyboard rate? + irq_install_handler(1, keyboard_handler); +} + +char keymap[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', + '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', + '\n', 17, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', + 14, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 14, '*', + 0, // Alt key + ' ', // Space bar + 15, // Caps lock + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F keys + 0, // Num lock + 0, // Scroll lock + 0, // Home key + 0, // Up arrow + 0, // Page up + '-', + 0, // Left arrow + 0, + 0, // Right arrow + '+', + 0, // End key + 0, // Down arrow + 0, // Page down + 0, // Insert key + 0, // Delete key + 0, 0, 0, + 0, // F11 + 0, // F12 + 0, // Other keys +}; diff --git a/kernel/drivers/serial.c b/kernel/drivers/serial.c new file mode 100644 index 0000000..dcee4dd --- /dev/null +++ b/kernel/drivers/serial.c @@ -0,0 +1,32 @@ +#include <cpu.h> +#include <def.h> +#include <str.h> + +void serial_install() +{ + outb(0x3f8 + 1, 0x00); + outb(0x3f8 + 3, 0x80); + outb(0x3f8 + 0, 0x03); + outb(0x3f8 + 1, 0x00); + outb(0x3f8 + 3, 0x03); + outb(0x3f8 + 2, 0xC7); + outb(0x3f8 + 4, 0x0B); +} + +int is_transmit_empty() +{ + return inb(0x3f8 + 5) & 0x20; +} + +void serial_put(char ch) +{ + while (is_transmit_empty() == 0) + ; + outb(0x3f8, (u8)ch); +} + +void serial_print(const char *data) +{ + for (u32 i = 0; i < strlen(data); i++) + serial_put(data[i]); +} diff --git a/kernel/drivers/timer.c b/kernel/drivers/timer.c new file mode 100644 index 0000000..a3b4137 --- /dev/null +++ b/kernel/drivers/timer.c @@ -0,0 +1,39 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#include <cpu.h> +#include <def.h> +#include <interrupts.h> + +static u32 timer_ticks = 0; + +void timer_phase(int hz) +{ + int divisor = 3579545 / 3 / hz; + outb(0x43, 0x36); // 01 10 11 0b // CTR, RW, MODE, BCD + outb(0x40, divisor & 0xFF); + outb(0x40, divisor >> 8); +} + +// Executed 1000 times per second +void timer_handler() +{ + timer_ticks++; +} + +// "Delay" function with CPU sleep +void timer_wait(u32 ticks) +{ + u32 eticks; + + eticks = timer_ticks + ticks; + while (timer_ticks < eticks) { + __asm__("sti//hlt//cli"); + } +} + +// Install timer handler into IRQ0 +void timer_install() +{ + timer_phase(1000); + irq_install_handler(0, timer_handler); +} diff --git a/kernel/drivers/vesa.c b/kernel/drivers/vesa.c new file mode 100644 index 0000000..9402664 --- /dev/null +++ b/kernel/drivers/vesa.c @@ -0,0 +1,40 @@ +#include <def.h> +#include <vesa.h> + +void vesa_draw_rectangle(int x1, int y1, int x2, int y2, const u32 color[3]) +{ + int pos1 = x1 * vbe_bpl + y1 * vbe_pitch; + u8 *draw = &fb[pos1]; + for (int i = 0; i <= y2 - y1; i++) { + for (int j = 0; j <= x2 - x1; j++) { + draw[vbe_bpl * j] = color[2]; + draw[vbe_bpl * j + 1] = color[1]; + draw[vbe_bpl * j + 2] = color[0]; + } + draw += vbe_pitch; + } +} + +void vesa_set_pixel(u16 x, u16 y, const u32 color[3]) +{ + u8 pos = x * vbe_bpl + y * vbe_pitch; + u8 *draw = &fb[pos]; + draw[pos] = (char)color[2]; + draw[pos + 1] = (char)color[1]; + draw[pos + 2] = (char)color[0]; +} + +void vesa_fill(const u32 color[3]) +{ + vesa_draw_rectangle(0, 0, vbe->width - 1, vbe->height - 1, color); +} + +void vesa_init(struct vbe *info) +{ + vbe = info; + vbe_height = vbe->height; + vbe_width = vbe->width; + vbe_bpl = vbe->bpp >> 3; + vbe_pitch = vbe->pitch; + fb = (u8 *)vbe->framebuffer; +} |