diff options
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r-- | arch/i386/kernel/gdt.c | 58 | ||||
-rw-r--r-- | arch/i386/kernel/idt.c | 152 | ||||
-rw-r--r-- | arch/i386/kernel/isr.s | 129 | ||||
-rw-r--r-- | arch/i386/kernel/keyboard.c | 8 | ||||
-rw-r--r-- | arch/i386/kernel/paging.c | 78 | ||||
-rw-r--r-- | arch/i386/kernel/pic.c | 16 | ||||
-rw-r--r-- | arch/i386/kernel/syscall.c | 48 | ||||
-rw-r--r-- | arch/i386/kernel/timer.c | 6 |
8 files changed, 414 insertions, 81 deletions
diff --git a/arch/i386/kernel/gdt.c b/arch/i386/kernel/gdt.c new file mode 100644 index 0000000..c0cf127 --- /dev/null +++ b/arch/i386/kernel/gdt.c @@ -0,0 +1,58 @@ +#include <kernel/gdt.h> +#include <kernel/asm.h> +#include <kernel/string.h> + +struct gdt_entry desc[6]; +struct gdt_ptr gp; +struct tss_entry tss_entry; + +void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + desc[num].base_low = (base & 0xFFFF); + desc[num].base_middle = (base >> 16) & 0xFF; + desc[num].base_high = (base >> 24) & 0xFF; + + desc[num].limit_low = (limit & 0xFFFF); + desc[num].gran = (limit >> 16) & 0x0F; + desc[num].gran |= (gran & 0xF0); + desc[num].access = access; +} + +void write_tss(int num, uint32_t ss0, uint32_t esp0) { + uint32_t base = (uint32_t)&tss_entry; + uint32_t limit = base + sizeof(struct tss_entry); + + gdt_set_gate(num, base, limit, 0x89, 0x00); + memset(&tss_entry, 0x0, sizeof(tss_entry)); + + tss_entry.ss0 = ss0; + tss_entry.esp0 = esp0; + tss_entry.cs = 0x0B; + tss_entry.ss = 0x13; + tss_entry.ds = 0x13; + tss_entry.es = 0x13; + tss_entry.fs = 0x13; + tss_entry.gs = 0x13; + tss_entry.iomap_base = sizeof(tss_entry); +} + +void set_kernel_esp(uint32_t esp) { + tss_entry.esp0 = esp; +} + +void gdt_install(void) { + gp.limit = (sizeof(struct gdt_entry) * 6) - 1; + gp.base = (uint32_t)&desc; + + gdt_set_gate(0, 0, 0, 0, 0); + gdt_set_gate(1, 0, 0xFFFFF, 0x9A, 0xCF); + gdt_set_gate(2, 0, 0xFFFFF, 0x92, 0xCF); + gdt_set_gate(3, 0, 0xFFFFF, 0xFA, 0xCF); + gdt_set_gate(4, 0, 0xFFFFF, 0xF2, 0xCF); + + uint32_t esp; + __asm__ volatile("movl %%esp, %0" : "=r"(esp)); + write_tss(5, 0x10, esp); + + flush_gdt(); + flush_tss(); +} diff --git a/arch/i386/kernel/idt.c b/arch/i386/kernel/idt.c new file mode 100644 index 0000000..5c0766c --- /dev/null +++ b/arch/i386/kernel/idt.c @@ -0,0 +1,152 @@ +#include <kernel/idt.h> +#include <kernel/syscall.h> +#include <kernel/panic.h> +#include <kernel/gdt.h> +#include <kernel/asm.h> +#include <kernel/io.h> +#include <kernel/pic.h> +#include <kernel/string.h> +#include <kernel/paging.h> +#include <stdint.h> + +__attribute__((aligned(0x10))) +struct idt_entry idt[256]; +struct idt_ptr idtr; + +const char* exceptions[] = { + "Division by zero", + "Debug", + "Non-maskable interrupt", + "Breakpoint", + "Overflow", + "Out-of-bounds", + "Invalid opcode", + "FPU not available", + "Double fault", + "RESERVED", + "Invalid TSS", + "Segment not present", + "Stack fault", + "General protection fault", + "Page fault", + "RESERVED", + "FPU exception", + "Alignment check", + "Machine check", + "FPU-SIMD exception", + "Virtualization exception", + "Control protection" + "RESERVED", + "Hypervisor injection", + "VMM exception", + "Security exception", + "RESERVED", + "Triple fault", + "RESERVED" +}; + +void exception_handler(struct regs *regs) { + switch (regs->isr_vector) { + case 0x00: + panic("Division by zero in kernel address space"); + break; + case 0x06: + panic("Invalid opcode in kernel address space"); + break; + case 0x08: + panic("Double fault in interrupt handler"); + break; + case 0x0D: + panic("Protection fault in kernel address space"); + break; + case 0x0E: + page_fault_handler(regs); + break; + default: + panic("Unhandled exception"); + } +} + +void interrupt_handler(struct regs regs) { + if (regs.isr_vector < 32) { + exception_handler(®s); + } else if (regs.isr_vector < 48) { + irq_dispatch(®s); + } else { + switch (regs.isr_vector) { + case 0x80: + handle_syscall(®s); + break; + default: + panic("Unmapped interrupt"); + } + } +} + +void idt_set_gate(uint8_t num, void (*handler)(void), uint16_t cs, uint8_t flags) { + struct idt_entry *desc = &idt[num]; + desc->isr_low = (uint16_t)(((uint32_t)handler >> 0) & 0xFFFF); + desc->isr_high = (uint16_t)(((uint32_t)handler >> 16) & 0xFFFF); + desc->reserved = 0; + desc->kernel_cs = cs; + desc->flags = flags; +} + +void idt_install(void) { + idtr.limit = (uint16_t)sizeof(struct idt_entry) * 256 - 1; + idtr.base = (uint32_t)idt; + + idt_set_gate(0x0, isr_stub_0, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1, isr_stub_1, 0x08, IDT_EXCEPTION); + idt_set_gate(0x2, isr_stub_2, 0x08, IDT_EXCEPTION); + idt_set_gate(0x3, isr_stub_3, 0x08, IDT_EXCEPTION); + idt_set_gate(0x4, isr_stub_4, 0x08, IDT_EXCEPTION); + idt_set_gate(0x5, isr_stub_5, 0x08, IDT_EXCEPTION); + idt_set_gate(0x6, isr_stub_6, 0x08, IDT_EXCEPTION); + idt_set_gate(0x7, isr_stub_7, 0x08, IDT_EXCEPTION); + idt_set_gate(0x8, isr_stub_8, 0x08, IDT_EXCEPTION); + idt_set_gate(0x9, isr_stub_9, 0x08, IDT_EXCEPTION); + idt_set_gate(0xA, isr_stub_10, 0x08, IDT_EXCEPTION); + idt_set_gate(0xB, isr_stub_11, 0x08, IDT_EXCEPTION); + idt_set_gate(0xC, isr_stub_12, 0x08, IDT_EXCEPTION); + idt_set_gate(0xD, isr_stub_13, 0x08, IDT_EXCEPTION); + idt_set_gate(0xE, isr_stub_14, 0x08, IDT_EXCEPTION); + idt_set_gate(0xF, isr_stub_15, 0x08, IDT_EXCEPTION); + idt_set_gate(0x10, isr_stub_16, 0x08, IDT_EXCEPTION); + idt_set_gate(0x11, isr_stub_17, 0x08, IDT_EXCEPTION); + idt_set_gate(0x12, isr_stub_18, 0x08, IDT_EXCEPTION); + idt_set_gate(0x13, isr_stub_19, 0x08, IDT_EXCEPTION); + idt_set_gate(0x14, isr_stub_20, 0x08, IDT_EXCEPTION); + idt_set_gate(0x15, isr_stub_21, 0x08, IDT_EXCEPTION); + idt_set_gate(0x16, isr_stub_22, 0x08, IDT_EXCEPTION); + idt_set_gate(0x17, isr_stub_23, 0x08, IDT_EXCEPTION); + idt_set_gate(0x18, isr_stub_24, 0x08, IDT_EXCEPTION); + idt_set_gate(0x19, isr_stub_25, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1A, isr_stub_26, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1B, isr_stub_27, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1C, isr_stub_28, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1D, isr_stub_29, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1E, isr_stub_30, 0x08, IDT_EXCEPTION); + idt_set_gate(0x1F, isr_stub_31, 0x08, IDT_EXCEPTION); + + idt_set_gate(0x20, irq_stub_0, 0x08, IDT_INTERRUPT); + idt_set_gate(0x21, irq_stub_1, 0x08, IDT_INTERRUPT); + idt_set_gate(0x22, irq_stub_2, 0x08, IDT_INTERRUPT); + idt_set_gate(0x23, irq_stub_3, 0x08, IDT_INTERRUPT); + idt_set_gate(0x24, irq_stub_4, 0x08, IDT_INTERRUPT); + idt_set_gate(0x25, irq_stub_5, 0x08, IDT_INTERRUPT); + idt_set_gate(0x26, irq_stub_6, 0x08, IDT_INTERRUPT); + idt_set_gate(0x27, irq_stub_7, 0x08, IDT_INTERRUPT); + idt_set_gate(0x28, irq_stub_8, 0x08, IDT_INTERRUPT); + idt_set_gate(0x29, irq_stub_9, 0x08, IDT_INTERRUPT); + idt_set_gate(0x2A, irq_stub_10, 0x08, IDT_INTERRUPT); + idt_set_gate(0x2B, irq_stub_11, 0x08, IDT_INTERRUPT); + idt_set_gate(0x2C, irq_stub_12, 0x08, IDT_INTERRUPT); + idt_set_gate(0x2D, irq_stub_13, 0x08, IDT_INTERRUPT); + idt_set_gate(0x2E, irq_stub_14, 0x08, IDT_INTERRUPT); + idt_set_gate(0x2F, irq_stub_15, 0x08, IDT_INTERRUPT); + + idt_set_gate(0x80, syscall_stub, 0x08, IDT_INTERRUPT); + + __asm__ volatile("lidt %0" : : "memory"(idtr)); +} diff --git a/arch/i386/kernel/isr.s b/arch/i386/kernel/isr.s new file mode 100644 index 0000000..55db35e --- /dev/null +++ b/arch/i386/kernel/isr.s @@ -0,0 +1,129 @@ +.section .text + +.macro isr_err_stub num +.global isr_stub_\num +.type isr_stub_\num, @function +isr_stub_\num: + cli + pushl $\num + jmp isr_frame_asm +.endm +.macro isr_no_err_stub num +.global isr_stub_\num +.type isr_stub_\num, @function +isr_stub_\num: + cli + pushl $0 + pushl $\num + jmp isr_frame_asm +.endm + +.macro irq_stub num +.global irq_stub_\num +.type irq_stub_\num, @function +irq_stub_\num: + cli + pushl $0 + pushl $\num+32 + jmp isr_frame_asm +.endm + +.global syscall_stub +syscall_stub: + cli + pushl $0 + pushl $0x80 + jmp isr_frame_asm + +isr_frame_asm: + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl %cr0, %eax + pushl %eax + movl %cr2, %eax + pushl %eax + movl %cr3, %eax + pushl %eax + movl %cr4, %eax + pushl %eax + + pushl %esp + call set_kernel_esp + addl $4, %esp + + cld + call interrupt_handler + + popl %eax + movl %eax, %cr4 + popl %eax + movl %eax, %cr3 + popl %eax + movl %eax, %cr2 + popl %eax + movl %eax, %cr0 + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + addl $8, %esp + + iret + +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 + +irq_stub 0 +irq_stub 1 +irq_stub 2 +irq_stub 3 +irq_stub 4 +irq_stub 5 +irq_stub 6 +irq_stub 7 +irq_stub 8 +irq_stub 9 +irq_stub 10 +irq_stub 11 +irq_stub 12 +irq_stub 13 +irq_stub 14 +irq_stub 15 diff --git a/arch/i386/kernel/keyboard.c b/arch/i386/kernel/keyboard.c index 4e4bc9b..96aea3a 100644 --- a/arch/i386/kernel/keyboard.c +++ b/arch/i386/kernel/keyboard.c @@ -100,6 +100,9 @@ static uint8_t* keymaps[4] = { keymap_control, }; +char keyboard_buffer[4096]; +int kbuf_pos = 0; + char keyboard_getchar(void) { static int shift = 0; uint8_t st = inb(KB_STAT); @@ -133,10 +136,9 @@ char keyboard_getchar(void) { return c; } -void keyboard_handler(struct isr_frame *frame) { +void keyboard_handler(void) { char c = keyboard_getchar(); - // TODO: actually put this in a buffer if (c != -1) - fb_putchar(c); + keyboard_buffer[kbuf_pos++]; return; } diff --git a/arch/i386/kernel/paging.c b/arch/i386/kernel/paging.c index 54539ac..b2a1392 100644 --- a/arch/i386/kernel/paging.c +++ b/arch/i386/kernel/paging.c @@ -10,63 +10,42 @@ static uintptr_t kend = (uintptr_t)&_kernel_end - 0xC0000000; static uintptr_t page_directory[1024] __attribute__((aligned(PAGE_SIZE))); static uintptr_t first_page_table[1024] __attribute__((aligned(PAGE_SIZE))); +static uintptr_t second_page_table[1024] __attribute__((aligned(PAGE_SIZE))); static int paging_enabled = 0; -static uint32_t dma_zone_bitmap[DMA_BITMAP_SZ]; -static uint32_t buddy_bitmap[BDY_BITMAP_SZ]; -static struct pfa_buddy first_buddy; - -static void _pfa_init(void) { - first_buddy.start = 0x01000000; - first_buddy.bitmap = buddy_bitmap; +uint32_t* init_page_table(uint32_t flags) { + uint32_t *ret = kmalloc(sizeof(uint32_t)*1024); + for (int i = 0; i < 1024; i++) + ret[i] = flags; } -static void _pfa_alloc(uintptr_t paddr) { - uintptr_t index = (paddr & 0xFFFFF000) / 4096 / 32; - uintptr_t bit = (paddr & 0xFFFFF000) / 4096 % 32; - uint32_t *bitmap; - if (paddr < 0x01000000) - bitmap = dma_zone_bitmap; - else - bitmap = first_buddy.bitmap; - - bitmap[index] |= (1 << bit); -} - -static void _pfa_free(uintptr_t paddr) { - uintptr_t index = (paddr & 0xFFFFF000) / 4096 / 32; - uintptr_t bit = (paddr & 0xFFFFF000) / 4096 % 32; - uint32_t *bitmap; - if (paddr < 0x01000000) - bitmap = dma_zone_bitmap; - else - bitmap = first_buddy.bitmap; - - bitmap[index] &= ~(1 << bit); +uint32_t* init_page_dir(uint32_t flags) { + uint32_t *ret = init_page_table(flags); + ret[0] = ((uintptr_t)&first_page_table - 0xC0000000) | 3; + ret[768] = ((uintptr_t)&second_page_table - 0xC0000000) | 3; } void paging_init(void) { - _pfa_init(); - for (int i = 0; i < 1024; i++) - page_directory[i] = 0x00000002; + for (int i = 0; i < 1024; i++) { + page_directory[i] = PD_RW; + first_page_table[i] = PD_RW; + second_page_table[i] = PD_RW; + } page_directory[1023] = ((uintptr_t)&page_directory - 0xC0000000) | 3; page_directory[0] = ((uintptr_t)&first_page_table - 0xC0000000) | 3; - page_directory[768] = ((uintptr_t)&first_page_table - 0xC0000000) | 3; - for (uintptr_t i = kstart; i < kend; i += 4096) { - _pfa_alloc(get_vaddr(i)); - map_page(page_directory, i, get_vaddr(i), 0x003); - } + page_directory[768] = ((uintptr_t)&second_page_table - 0xC0000000) | 3; + for (uintptr_t i = kstart; i < kend; i += PAGE_SIZE) + map_page(page_directory, i, i + 0xC0000000, 0x003); - load_page_dir(((uintptr_t)&page_directory) - 0xC0000000); - enable_paging(); + enable_paging(((uintptr_t)&page_directory) - 0xC0000000); paging_enabled = 1; return; } -void page_fault_handler(struct isr_frame *frame) { - uintptr_t errno = frame->errno; +void page_fault_handler(struct regs *regs) { + uintptr_t errno = regs->isr_err; uintptr_t fault_addr; __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr)); @@ -76,9 +55,9 @@ void page_fault_handler(struct isr_frame *frame) { int reserved = errno & ERR_RESERVED; int ifetch = errno & ERR_INST; + uintptr_t first_free; if (!present) - _pfa_alloc(fault_addr); - map_page(NULL, fault_addr, fault_addr, 0x003); + map_page(regs->cr3, fault_addr, fault_addr, PD_PRES | PD_RW | PD_USR); if (user) panic("Usermode attempted to read supervisor page"); if (rw) @@ -89,8 +68,17 @@ void page_fault_handler(struct isr_frame *frame) { panic("Task paging instruction fetch failure"); } -uintptr_t get_vaddr(uintptr_t paddr) { - return paddr + 0xC0000000; +uintptr_t get_paddr(uintptr_t vaddr) { + uint32_t pdindex = (uint32_t)vaddr >> 22; + uint32_t ptindex = (uint32_t)vaddr >> 12 & 0x03FF; + + uint32_t *pd = (uint32_t*)0xFFFFF000; + if (*pd & PD_PRES != 1) + return NULL; + uint32_t *pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex); + if (*pt & PD_PRES != 1) + return NULL; + return (uintptr_t)((pt[ptindex] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF)); } void map_page(uint32_t *pd, uintptr_t paddr, uintptr_t vaddr, uint32_t flags) { diff --git a/arch/i386/kernel/pic.c b/arch/i386/kernel/pic.c index 7a51763..3cf1d94 100644 --- a/arch/i386/kernel/pic.c +++ b/arch/i386/kernel/pic.c @@ -1,6 +1,6 @@ #include <kernel/pic.h> -static void (*irq_handlers[16])(struct isr_frame *frame); +static void (*irq_handlers[16])(struct regs *regs); void pic_eoi(uint8_t irq) { if (irq >= 8) @@ -24,27 +24,27 @@ void pic_remap(void) { outb(PIC2_DATA, a2); } -static uint16_t __pic_get_irq_reg(int ocw3) { +static uint16_t _pic_get_irq_reg(int ocw3) { outb(PIC1_COMMAND, ocw3); outb(PIC2_COMMAND, ocw3); return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND); } uint16_t pic_get_irr(void) { - return __pic_get_irq_reg(PIC_READ_IRR); + return _pic_get_irq_reg(PIC_READ_IRR); } uint16_t pic_get_isr(void) { - return __pic_get_irq_reg(PIC_READ_ISR); + return _pic_get_irq_reg(PIC_READ_ISR); } -void register_irq_handler(uint8_t irq, void (*handler)(struct isr_frame *frame)) { +void register_irq_handler(uint8_t irq, void (*handler)(struct regs *regs)) { irq_handlers[irq] = handler; } -void irq_dispatch(struct isr_frame *frame) { - (*irq_handlers[frame->vector-32])(frame); - pic_eoi(frame->vector-32); +void irq_dispatch(struct regs *regs) { + (*irq_handlers[regs->isr_vector-32])(regs); + pic_eoi(regs->isr_vector-32); return; } diff --git a/arch/i386/kernel/syscall.c b/arch/i386/kernel/syscall.c index 7bdb24b..27e1c60 100644 --- a/arch/i386/kernel/syscall.c +++ b/arch/i386/kernel/syscall.c @@ -1,32 +1,36 @@ #include <kernel/syscall.h> +#include <kernel/panic.h> +#include <kernel/framebuffer.h> +#include <kernel/keyboard.h> +#include <kernel/string.h> #include <kernel/io.h> #include <stddef.h> -int handle_syscall(struct isr_frame *frame) { - switch (frame->eax) { - case SYS_REBOOT: - kprintf("REBOOT NOT SUPPORTED\n"); - break; - default: - kprintf("Error: Invalid system call number: %d\n", frame->eax); - halt_catch_fire(frame); +extern char *keyboard_buffer; +extern uint32_t kbuf_pos; + +void sys_read(struct regs *regs) { + if (regs->ebx == 1) { + while (kbuf_pos > regs->edx); + memcpy((char*)regs->ecx, keyboard_buffer, regs->edx); } - return 0; } -void dump_reg(struct isr_frame *frame) { - kprintf("Registers at interrupt:\n"); - kprintf("\tEAX = %x\n", frame->eax); - kprintf("\tEBX = %x\n", frame->ebx); - kprintf("\tECX = %x\n", frame->ecx); - kprintf("\tEDX = %x\n", frame->edx); - kprintf("\tESI = %x\n", frame->esi); - kprintf("\tEDI = %x\n", frame->edi); - kprintf("\tEIP = %x\n", frame->eip); - kprintf("Current code selector: %x\n", frame->cs); +void sys_write(struct regs *regs) { + if (regs->ebx == 0) + fb_write((char*)regs->ecx, regs->edx); } -void dump_stack(uint32_t esp, size_t len) { - for (uint32_t i = 0; i < len; i++) - kprintf("%x:\t%x\n", esp+i, *(uint32_t*)(esp+i)); +int handle_syscall(struct regs *regs) { + switch (regs->eax) { + case SYS_READ: + sys_read(regs); + break; + case SYS_WRITE: + sys_write(regs); + break; + default: + panic("Invalid system call number"); + } + return 0; } diff --git a/arch/i386/kernel/timer.c b/arch/i386/kernel/timer.c index 9e53fbd..4aafed1 100644 --- a/arch/i386/kernel/timer.c +++ b/arch/i386/kernel/timer.c @@ -5,7 +5,7 @@ static uint32_t num_ticks = 0; -void timer_handler(struct isr_frame *frame) { +void timer_handler(struct regs *regs) { num_ticks++; if (num_ticks == 3) { num_ticks = 0; @@ -14,12 +14,12 @@ void timer_handler(struct isr_frame *frame) { } void timer_init(void) { - asm __volatile__("cli"); + disable_ints(); int divisor = 1193182 / 100; outb(0x43, 0x34); outb(0x40, divisor && 0xFF); outb(0x40, divisor && 0xFF00 >> 8); - asm __volatile__("sti"); + enable_ints(); //uint8_t read = 0; //outb(0x43, 0xE2); |