diff options
Diffstat (limited to 'kernel/arch/x86')
-rw-r--r-- | kernel/arch/x86/include/kernel/asm.h | 167 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/gdt.h | 53 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/idt.h | 31 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/paging.h | 45 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/pic.h | 44 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/pmem.h | 19 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/syscall.h | 34 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/timer.h | 9 | ||||
-rw-r--r-- | kernel/arch/x86/include/kernel/vmem.h | 17 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/gdt.c | 54 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/idt.c | 149 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/kmalloc.c | 70 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/multiboot.c | 49 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/paging.c | 130 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/pic.c | 79 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/pmem.c | 66 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/serial.c | 42 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/syscall.c | 25 | ||||
-rw-r--r-- | kernel/arch/x86/kernel/timer.c | 25 |
19 files changed, 1108 insertions, 0 deletions
diff --git a/kernel/arch/x86/include/kernel/asm.h b/kernel/arch/x86/include/kernel/asm.h new file mode 100644 index 0000000..18f53c4 --- /dev/null +++ b/kernel/arch/x86/include/kernel/asm.h @@ -0,0 +1,167 @@ +#ifndef I386_ASM_H +#define I386_ASM_H + +#include <kernel/gdt.h> +#include <stdint.h> +#include <cpuid.h> + +#define PCI_CONFIG_ADDR 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +#define COM_PORT 0x3F8 + +#define MAX_ISR 256 + +struct regs { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t esp; + + uint32_t cr0; + uint32_t cr2; + uint32_t cr3; + uint32_t cr4; +}; + +struct isr_frame { + uint32_t cr4; + uint32_t cr3; + uint32_t cr2; + uint32_t cr0; + + uint32_t edi; + uint32_t esi; + uint32_t edx; + uint32_t ecx; + uint32_t ebx; + uint32_t eax; + + uint32_t isr_vector; + uint32_t isr_err; + uint32_t eip; + uint32_t cs; + uint32_t eflags; +} __attribute__((packed)); + +struct cpuid_info { + char vendorID[12]; + uint32_t feat_ecx; + uint32_t feat_edx; +}; + +void isr_stub_0(void); +void isr_stub_1(void); +void isr_stub_2(void); +void isr_stub_3(void); +void isr_stub_4(void); +void isr_stub_5(void); +void isr_stub_6(void); +void isr_stub_7(void); +void isr_stub_8(void); +void isr_stub_9(void); +void isr_stub_10(void); +void isr_stub_11(void); +void isr_stub_12(void); +void isr_stub_13(void); +void isr_stub_14(void); +void isr_stub_15(void); +void isr_stub_16(void); +void isr_stub_17(void); +void isr_stub_18(void); +void isr_stub_19(void); +void isr_stub_20(void); +void isr_stub_21(void); +void isr_stub_22(void); +void isr_stub_23(void); +void isr_stub_24(void); +void isr_stub_25(void); +void isr_stub_26(void); +void isr_stub_27(void); +void isr_stub_28(void); +void isr_stub_29(void); +void isr_stub_30(void); +void isr_stub_31(void); + +void irq_stub_0(void); +void irq_stub_1(void); +void irq_stub_2(void); +void irq_stub_3(void); +void irq_stub_4(void); +void irq_stub_5(void); +void irq_stub_6(void); +void irq_stub_7(void); +void irq_stub_8(void); +void irq_stub_9(void); +void irq_stub_10(void); +void irq_stub_11(void); +void irq_stub_12(void); +void irq_stub_13(void); +void irq_stub_14(void); +void irq_stub_15(void); + +void isr_stub_128(void); + +void enable_paging(uint32_t new_cr3); +int cpuid_check(void); +void flush_gdt(void); + +static inline void cpuid(int code, uint32_t *ecx, uint32_t *ebx) { + __asm__ volatile("cpuid" : "=a"(*ecx), "=d"(*ebx) : "a"(code) : "ecx","ebx"); +} + +static inline void outb(uint16_t port, uint8_t value) { + __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); +} + +static inline void outw(uint16_t port, uint16_t value) { + __asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port)); +} + +static inline void outl(uint16_t port, uint32_t value) { + __asm__ volatile("outl %0, %1" : : "a"(value), "Nd"(port)); +} + +static inline uint8_t inb(uint16_t port) { + uint8_t ret; + __asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline uint16_t inw(uint16_t port) { + uint16_t ret; + __asm__ volatile("inw %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline uint32_t inl(uint16_t port) { + uint32_t ret; + __asm__ volatile("inl %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline void enable_ints(void) { + __asm__ volatile("sti"); +} + +static inline void disable_ints(void) { + __asm__ volatile("cli"); +} + +static inline void flush_tss(void) { + __asm__ volatile("movw $0x28, %ax; ltr %ax"); +} + +static inline void flush_tlb(void) { + __asm__ volatile("movl %cr3, %eax; movl %eax, %cr3"); +} + +static inline void invlpg(void *addr) { + __asm__ volatile("invlpg (%0)" : : "b"(addr) : "memory"); +} + +#endif diff --git a/kernel/arch/x86/include/kernel/gdt.h b/kernel/arch/x86/include/kernel/gdt.h new file mode 100644 index 0000000..aa05408 --- /dev/null +++ b/kernel/arch/x86/include/kernel/gdt.h @@ -0,0 +1,53 @@ +#ifndef I386_GDT_H +#define I386_GDT_H + +#include <stdint.h> + +struct gdt_entry { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t gran; + uint8_t base_high; +} __attribute__((packed)); + +struct gdt_ptr { + uint16_t limit; + uint64_t base; +} __attribute__((packed)); + +struct tss_entry { + uint32_t link; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldtr; + uint16_t trap; + uint16_t iomap_base; +} __attribute__((packed)); + +void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran); +void write_tss(int num, uint32_t ss0, uint32_t esp0); +void set_kernel_esp(uint32_t esp); +void gdt_install(void); + +#endif diff --git a/kernel/arch/x86/include/kernel/idt.h b/kernel/arch/x86/include/kernel/idt.h new file mode 100644 index 0000000..29ec39f --- /dev/null +++ b/kernel/arch/x86/include/kernel/idt.h @@ -0,0 +1,31 @@ +#ifndef I386_IDT_H +#define I386_IDT_H + +#include <stdint.h> + +#define SEGMENT_PRESENT 0x80 +#define SEGMENT_RING0 0x00 +#define SEGMENT_RING3 0x60 +#define SEGMENT_STORAGE 0x00 +#define SEGMENT_INTERRUPT 0x0E +#define IDT_EXCEPTION (SEGMENT_PRESENT | SEGMENT_INTERRUPT) +#define IDT_INTERRUPT (SEGMENT_PRESENT | SEGMENT_INTERRUPT) + +#define IDT_MAX_DESCRIPTORS 256 + +struct idt_entry { + uint16_t isr_low; + uint16_t kernel_cs; + uint8_t reserved; + uint8_t flags; + uint16_t isr_high; +} __attribute__((packed)); + +struct idt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +void idt_install(void); + +#endif diff --git a/kernel/arch/x86/include/kernel/paging.h b/kernel/arch/x86/include/kernel/paging.h new file mode 100644 index 0000000..3a3c298 --- /dev/null +++ b/kernel/arch/x86/include/kernel/paging.h @@ -0,0 +1,45 @@ +#ifndef I386_PAGING_H +#define I386_PAGING_H + +#include <kernel/asm.h> +#include <stdint.h> + +#define PAGE_SIZE 4096 + +#define PD_PRES 0x0001 +#define PD_RW 0x0002 +#define PD_USR 0x0004 +#define PD_PWT 0x0008 +#define PD_PCD 0x0010 +#define PD_ACC 0x0020 +#define PD_DIRTY 0x0040 +#define PD_PS 0x0080 +#define PD_GLOB 0x0100 +#define PD_PAT 0x1000 + +#define ERR_PRESENT 0x1 +#define ERR_RW 0x2 +#define ERR_USER 0x4 +#define ERR_RESERVED 0x8 +#define ERR_INST 0x10 + +#define PGROUNDUP(size) (((size)+PAGE_SIZE-1) & ~(PAGE_SIZE-1)) +#define PGROUNDDN(size) (((size)) & ~(PAGE_SIZE-1)) + +#define GET_PADDR(x) (((uint32_t)(x)) - 0xC0000000) +#define GET_VADDR(x) (((uint32_t)(x)) + 0xC0000000) + +#define GET_PDX(x) ((uintptr_t)(x) >> 22) +#define GET_PTX(x) (((uintptr_t)(x) >> 12) & 0x03FF) + +uintptr_t get_physaddr(void *vaddr); + +void paging_init(void); + +uintptr_t init_page_directory(void); +void map_page(uintptr_t paddr, uintptr_t vaddr, uint32_t flags); +void unmap_page(uintptr_t vaddr); + +void page_fault_handler(struct isr_frame *frame); + +#endif diff --git a/kernel/arch/x86/include/kernel/pic.h b/kernel/arch/x86/include/kernel/pic.h new file mode 100644 index 0000000..187d553 --- /dev/null +++ b/kernel/arch/x86/include/kernel/pic.h @@ -0,0 +1,44 @@ +#ifndef I386_PIC_H +#define I386_PIC_H + +#include <kernel/asm.h> +#include <stdint.h> + +#define PIC1 0x20 +#define PIC2 0x28 +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1+1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2+1) + +#define ICW1_ICW4 0x01 +#define ICW1_SINGLE 0x02 +#define ICW1_INTERVAL4 0x04 +#define ICW1_LEVEL 0x08 +#define ICW1_INIT 0x10 + +#define ICW4_8086 0x01 +#define ICW4_AUTO 0x02 +#define ICW4_BUF_SLAVE 0x08 +#define ICW4_BUF_MASTER 0x0C +#define ICW4_SFNM 0x10 + +#define PIC_READ_IRR 0x0A +#define PIC_READ_ISR 0x0B + +static inline void io_wait(void) { + outb(0x80, 0); +} + +void pic_eoi(uint8_t irq); +void pic_remap(void); +uint16_t pic_get_irr(void); +uint16_t pic_get_isr(void); + +void register_irq_handler(uint8_t irq, void (*handler)(struct isr_frame *frame)); +void irq_dispatch(struct isr_frame *frame); + +void irq_set_mask(uint8_t irq); +void irq_clear_mask(uint8_t irq); + +#endif diff --git a/kernel/arch/x86/include/kernel/pmem.h b/kernel/arch/x86/include/kernel/pmem.h new file mode 100644 index 0000000..ea4fe29 --- /dev/null +++ b/kernel/arch/x86/include/kernel/pmem.h @@ -0,0 +1,19 @@ +#ifndef I386_PMEM_H +#define I386_PMEM_H + +#include <stdint.h> +#include <stddef.h> + +struct pfa_page { + struct pfa_page *next; +}; + +void pfa_init(struct mboot_info *header); + +uintptr_t pfa_alloc_dma(size_t num_pages); +uintptr_t pfa_alloc(size_t num_pages); + +void pfa_free_dma(uintptr_t paddr, size_t num_pages); +void pfa_free(uintptr_t paddr, size_t num_pages); + +#endif diff --git a/kernel/arch/x86/include/kernel/syscall.h b/kernel/arch/x86/include/kernel/syscall.h new file mode 100644 index 0000000..a657527 --- /dev/null +++ b/kernel/arch/x86/include/kernel/syscall.h @@ -0,0 +1,34 @@ +#ifndef I386_SYSCALL_H +#define I386_SYSCALL_H + +#include <kernel/asm.h> +#include <stdint.h> +#include <stddef.h> + +// Unix standard calls +#define SYS_FORK 1 +#define SYS_EXIT 2 +#define SYS_WAIT 3 +#define SYS_PIPE 4 +#define SYS_READ 5 +#define SYS_WRITE 6 +#define SYS_KILL 7 +#define SYS_FSTAT 8 +#define SYS_CHDIR 9 +#define SYS_DUP 10 +#define SYS_GETPID 11 +#define SYS_SLEEP 12 +#define SYS_OPEN 13 +#define SYS_MKNOD 14 +#define SYS_UNLINK 15 +#define SYS_LINK 16 +#define SYS_MKDIR 17 +#define SYS_CLOSE 18 +#define SYS_EXEC 19 + +#define SYS_HALT 87 +#define SYS_REBOOT 88 + +void handle_syscall(struct isr_frame *frame); + +#endif diff --git a/kernel/arch/x86/include/kernel/timer.h b/kernel/arch/x86/include/kernel/timer.h new file mode 100644 index 0000000..c0b3a73 --- /dev/null +++ b/kernel/arch/x86/include/kernel/timer.h @@ -0,0 +1,9 @@ +#ifndef I386_TIMER_H +#define I386_TIMER_H + +#include <kernel/asm.h> + +void timer_handler(struct isr_frame *frame); +void timer_init(void); + +#endif diff --git a/kernel/arch/x86/include/kernel/vmem.h b/kernel/arch/x86/include/kernel/vmem.h new file mode 100644 index 0000000..94aa32d --- /dev/null +++ b/kernel/arch/x86/include/kernel/vmem.h @@ -0,0 +1,17 @@ +#ifndef I386_VMEM_H +#define I386_VMEM_H + +extern uintptr_t _kernel_start; +extern uintptr_t _kernel_end; + +#define KSTART ((uintptr_t)&_kernel_start) +#define KEND ((uintptr_t)&_kernel_end - 0xC0000000) + +#define KHEAP_START (GET_VADDR(KEND) + 0x2000) +#define KHEAP_STOP 0xFF7FF000 + +#define PAGE_DIR_MAP 0xFFFFF000 +#define PAGE_TAB_MAP 0xFFC00000 +#define PAGE_TMP_MAP 0xFFBFF000 + +#endif diff --git a/kernel/arch/x86/kernel/gdt.c b/kernel/arch/x86/kernel/gdt.c new file mode 100644 index 0000000..57424aa --- /dev/null +++ b/kernel/arch/x86/kernel/gdt.c @@ -0,0 +1,54 @@ +#include <kernel/gdt.h> +#include <kernel/asm.h> +#include <libk/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) { + uint64_t base = (uint64_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 gdt_install(void) { + gp.limit = (sizeof(struct gdt_entry) * 6) - 1; + gp.base = (uint64_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); + + uint64_t rsp; + __asm__ volatile("movq %%rsp, %0" : "=r"(rsp)); + write_tss(5, 0x10, rsp); + + flush_gdt(); + flush_tss(); +} diff --git a/kernel/arch/x86/kernel/idt.c b/kernel/arch/x86/kernel/idt.c new file mode 100644 index 0000000..a178801 --- /dev/null +++ b/kernel/arch/x86/kernel/idt.c @@ -0,0 +1,149 @@ +#include <kernel/idt.h> +#include <kernel/interrupt.h> +#include <kernel/syscall.h> +#include <kernel/panic.h> +#include <kernel/gdt.h> +#include <kernel/asm.h> +#include <kernel/pic.h> +#include <kernel/paging.h> +#include <libk/io.h> +#include <libk/string.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 isr_frame *frame) { + switch (frame->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(frame); + break; + default: + panic("Unhandled exception"); + } +} + +void generic_handler(struct isr_frame *frame) { + kprintf("No handler registered for IRQ %d\n", frame->isr_vector); + if (frame->isr_vector > 32 && frame->isr_vector < 48) + pic_eoi(frame->isr_vector-32); +} + +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; + + for (int i = 0; i < 32; i++) + register_isr_handler(i, exception_handler); + for (int i = 32; i < 224; i++) + register_isr_handler(i, generic_handler); + register_isr_handler(0x80, handle_syscall); + + 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, isr_stub_128, 0x08, IDT_INTERRUPT); + + __asm__ volatile("lidt %0" : : "memory"(idtr)); +} diff --git a/kernel/arch/x86/kernel/kmalloc.c b/kernel/arch/x86/kernel/kmalloc.c new file mode 100644 index 0000000..9e5254c --- /dev/null +++ b/kernel/arch/x86/kernel/kmalloc.c @@ -0,0 +1,70 @@ +#include <libk/kmalloc.h> +#include <kernel/paging.h> +#include <kernel/pmem.h> +#include <kernel/asm.h> +#include <kernel/vmem.h> +#include <kernel/panic.h> +#include <stdint.h> + +static uintptr_t heap_start = KEND + 0xC0001000; +static uintptr_t heap_end = 0xFFBFF000; + +static void *kbrk = NULL; +static struct mem_block *first = NULL; + +void _request_page(void) { + uintptr_t paddr = pfa_alloc(1); + uintptr_t vaddr = PGROUNDDN((uintptr_t)kbrk + PAGE_SIZE); + kbrk += PAGE_SIZE; + map_page(paddr, vaddr, PD_PRES | PD_RW); +} + +void kmalloc_init(void) { + kbrk = PGROUNDDN(heap_start); + _request_page(); + first = (struct mem_block*)kbrk; + first->start = (uintptr_t)kbrk + sizeof(struct mem_block); + first->size = 0; + first->alloc = 1; + first->next = NULL; +} + +void* kmalloc(size_t sz) { + if (kbrk == NULL) + panic("Attmpted to malloc before initialization"); + if ((uintptr_t)kbrk >= heap_end) + return NULL; + + struct mem_block *temp = first; + while (temp->next != NULL) { + if (temp->next->size <= sz && temp->next->alloc == 0) { + temp->next->alloc = 1; + return (void*)temp->next->start; + } + temp = temp->next; + } + + temp->next = (struct mem_block*)((uintptr_t)temp + sizeof(struct mem_block) + temp->size); + if (temp->next > kbrk) + _request_page(); + temp->next->prev = temp; + temp->next->start = (uintptr_t)(temp->next + sizeof(struct mem_block)); + temp->next->size = sz; + temp->next->alloc = 1; + temp->next->next = NULL; + return (void*)temp->start; +} + +void kfree(void *ptr) { + if (ptr == NULL) + return; + struct mem_block *temp = first; + while (temp != NULL) { + if (temp->start == (uintptr_t)ptr) { + temp->alloc = 0; + return; + } + temp = temp->next; + } + panic("Attempted to free memory not alloc'd"); +} diff --git a/kernel/arch/x86/kernel/multiboot.c b/kernel/arch/x86/kernel/multiboot.c new file mode 100644 index 0000000..dedf163 --- /dev/null +++ b/kernel/arch/x86/kernel/multiboot.c @@ -0,0 +1,49 @@ +#include <kernel/multiboot.h> +#include <kernel/asm.h> +#include <kernel/gdt.h> +#include <kernel/idt.h> +#include <kernel/pic.h> +#include <kernel/paging.h> +#include <kernel/pmem.h> +#include <kernel/timer.h> +#include <kernel/panic.h> +#include <kernel/vmem.h> +#include <kernel/video/framebuffer.h> +#include <libk/io.h> +#include <libk/string.h> +#include <libk/kmalloc.h> + +void kernel_main(char *cmdline); + +void i386_entry(uint32_t mboot_magic, struct mboot_info *header) { + map_page(0xB8000, (uintptr_t)VGA_MEMORY, PD_RW); + fb_init(); + + if (mboot_magic != MBOOT_LOADER_MAGIC) { + disable_ints(); + panic("Not booted with multiboot bootloader"); + } + + map_page(0x9000, 0x9000, PD_RW); + if (!(header->flags >> 6 & 0x1)) { + disable_ints(); + panic("Physical memory map not provided by bootloader"); + } + + char cmdline[4096]; + map_page(header->cmdline, PAGE_TMP_MAP, 0); + memcpy(cmdline, (char*)PAGE_TMP_MAP, strlen((char*)PAGE_TMP_MAP)); + unmap_page(PAGE_TMP_MAP); + pfa_init(header); + gdt_install(); + idt_install(); + paging_init(); + map_page(0xB8000, (uintptr_t)VGA_MEMORY, PD_RW); + pic_remap(); + timer_init(); + + enable_ints(); + kernel_main(cmdline); + + while (1); +} diff --git a/kernel/arch/x86/kernel/paging.c b/kernel/arch/x86/kernel/paging.c new file mode 100644 index 0000000..a0bbb92 --- /dev/null +++ b/kernel/arch/x86/kernel/paging.c @@ -0,0 +1,130 @@ +#include <kernel/paging.h> +#include <kernel/asm.h> +#include <kernel/vmem.h> +#include <kernel/pmem.h> +#include <kernel/panic.h> +#include <kernel/syscall.h> +#include <libk/io.h> +#include <libk/string.h> + +static int paging_enabled = 0; + +void paging_init(void) { + if (paging_enabled == 1) + return; + + uintptr_t phys_pt = pfa_alloc(1); + map_page(phys_pt, PAGE_TMP_MAP, PD_PRES | PD_RW); + uintptr_t *pt = (uintptr_t*)PAGE_TMP_MAP; + for (uintptr_t i = KSTART; i < KEND; i += PAGE_SIZE) + pt[GET_PTX(GET_VADDR(i))] = i | PD_PRES; + unmap_page(PAGE_TMP_MAP); + + uintptr_t temp_pt = pfa_alloc(1); + + uintptr_t phys_pd = pfa_alloc(1); + map_page(phys_pd, PAGE_TMP_MAP, PD_PRES | PD_RW); + uintptr_t *pd = (uintptr_t*)PAGE_TMP_MAP; + pd[GET_PDX(GET_VADDR(KSTART))] = phys_pt | PD_PRES | PD_RW; + pd[GET_PDX(PAGE_TMP_MAP)] = temp_pt | PD_PRES | PD_RW; + pd[1023] = phys_pd | PD_PRES | PD_RW; + unmap_page(PAGE_TMP_MAP); + + enable_paging(phys_pd); + paging_enabled = 1; + return; +} + +void init_page_table(int pdindex, uint32_t flags) { + uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP; + if ((pd[pdindex] & PD_PRES) != 0) + return; + + uintptr_t paddr = pfa_alloc(1); + pd[pdindex] = paddr | PD_PRES | PD_RW | flags; + + uintptr_t *pt = ((uintptr_t*)PAGE_TAB_MAP) + (pdindex << 12); + pd[GET_PDX(pt)] = paddr | PD_PRES | PD_RW; +} + +uintptr_t init_page_directory(void) { + uintptr_t ret = pfa_alloc(1); + map_page(ret, PAGE_TMP_MAP, PD_RW); + + uintptr_t *new_pd = (uintptr_t*)PAGE_TMP_MAP; + uintptr_t *cur_pd = (uintptr_t*)PAGE_DIR_MAP; + int kernel_pdx = GET_PDX(GET_VADDR(KSTART)); + new_pd[kernel_pdx] = cur_pd[kernel_pdx]; + + unmap_page(PAGE_TMP_MAP); + return ret; +} + +void map_page(uintptr_t paddr, uintptr_t vaddr, uint32_t flags) { + paddr = PGROUNDDN(paddr); + vaddr = PGROUNDDN(vaddr); + + int pdindex = GET_PDX(vaddr); + int ptindex = GET_PTX(vaddr); + + uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP; + if ((pd[pdindex] & PD_PRES) == 0) + init_page_table(pdindex, 0); + + uintptr_t *pt = (uintptr_t*)(PAGE_TAB_MAP + (pdindex << 12)); + pt[ptindex] = paddr | PD_PRES | flags; + invlpg((void*)vaddr); +} + +void unmap_page(uintptr_t vaddr) { + uintptr_t pdindex = GET_PDX(vaddr); + uintptr_t ptindex = GET_PTX(vaddr); + + uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP; + if ((pd[pdindex] & PD_PRES) == 0) + return; + + uintptr_t *pt = (uintptr_t*)(PAGE_TAB_MAP + (pdindex << 12)); + pt[ptindex] = 0; + invlpg((void*)vaddr); +} + +void page_fault_handler(struct isr_frame *frame) { + uintptr_t fault_addr; + __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr)); + + kprintf("Faulting address: %x\n", fault_addr); + panic("Page fault not operational"); + switch (frame->isr_err) { + case 0: + //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES); + break; + case 1: + panic("Kernel process caused protection fault on read\n"); + break; + case 2: + //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_RW); + break; + case 3: + panic("Kernel process caused protection fault on write\n"); + break; + case 4: + //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_USR); + break; + case 5: + // TODO: instead of panicking, kill process + panic("User process caused protection fault on read\n"); + break; + case 6: + //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_RW | PD_USR); + break; + case 7: + // TODO: see case 101 + panic("USER process caused protection fault on write\n"); + break; + default: + kprintf("Unknown paging error occured on address %x\n", fault_addr); + panic("Paging error"); + break; + } +} diff --git a/kernel/arch/x86/kernel/pic.c b/kernel/arch/x86/kernel/pic.c new file mode 100644 index 0000000..0d29473 --- /dev/null +++ b/kernel/arch/x86/kernel/pic.c @@ -0,0 +1,79 @@ +#include <kernel/pic.h> + +static void (*irq_handlers[16])(struct isr_frame *frame); + +void pic_eoi(uint8_t irq) { + if (irq >= 8) + outb(PIC2_COMMAND, 0x20); + outb(PIC1_COMMAND, 0x20); +} + +void pic_remap(void) { + unsigned char a1 = inb(PIC1_DATA); + unsigned char a2 = inb(PIC2_DATA); + + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + outb(PIC1_DATA, PIC1); + outb(PIC2_DATA, PIC2); + outb(PIC1_DATA, 4); + outb(PIC2_DATA, 2); + outb(PIC1_DATA, ICW4_8086); + outb(PIC2_DATA, ICW4_8086); + outb(PIC1_DATA, a1); + outb(PIC2_DATA, a2); +} + +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); +} + +uint16_t pic_get_isr(void) { + return _pic_get_irq_reg(PIC_READ_ISR); +} + +void register_irq_handler(uint8_t irq, void (*handler)(struct isr_frame *frame)) { + irq_handlers[irq] = handler; +} + +void irq_dispatch(struct isr_frame *frame) { + (*irq_handlers[frame->isr_vector-32])(frame); + pic_eoi(frame->isr_vector-32); + return; +} + +void irq_set_mask(uint8_t irq) { + uint16_t port; + uint8_t data; + + if (irq < 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + + data = inb(port) | (1 << irq); + outb(port, data); +} + +void irq_clear_mask(uint8_t irq) { + uint16_t port; + uint8_t data; + + if (irq < 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + + data = inb(port) & ~(1 << irq); + outb(port, data); +} diff --git a/kernel/arch/x86/kernel/pmem.c b/kernel/arch/x86/kernel/pmem.c new file mode 100644 index 0000000..edf71d9 --- /dev/null +++ b/kernel/arch/x86/kernel/pmem.c @@ -0,0 +1,66 @@ +#include <kernel/pmem.h> +#include <kernel/asm.h> +#include <kernel/vmem.h> +#include <kernel/panic.h> +#include <kernel/paging.h> +#include <libk/io.h> +#include <libk/string.h> + +static uintptr_t bitmap[5]; +static struct pfa_page freelist; + +void pfa_init(struct mboot_info *header) { + struct mboot_mmap_entry *mme; + for (uintptr_t i = 0; i < header->mmap_length; i += sizeof(struct mboot_mmap_entry)) { + mme = (struct mboot_mmap_entry*)(header->mmap_addr + i); + if (mme->type == MBOOT_MEM_AVAILABLE) + pfa_free(mme->addr_low, mme->len_low / PAGE_SIZE); + } +} + +uintptr_t pfa_alloc_dma(size_t num_pages) { +} + +uintptr_t pfa_alloc(size_t num_pages) { + struct pfa_page *temp = (struct pfa_page*)PAGE_TMP_MAP; + map_page(freelist.next, PAGE_TMP_MAP, PD_PRES | PD_RW); + uintptr_t ret = freelist.next; + freelist.next = temp->next; + memset(temp, 0, 32); + unmap_page(PAGE_TMP_MAP); + return ret; +} + +void pfa_free_dma(uintptr_t paddr, size_t num_pages) { + if (paddr % PAGE_SIZE != 0) + panic("Task attempted to free non-aligned memory"); + if (paddr >= KSTART && paddr < KEND) + return; + if (paddr >= 0x00080000 && paddr < 0x00100000) + return; + + int index = 0; + int bit = 0; + for (uintptr_t i = paddr; i < paddr + (num_pages * PAGE_SIZE); i += PAGE_SIZE) { + index = i / PAGE_SIZE / 32; + bit = i / PAGE_SIZE % 32; + bitmap[index] |= 1 << bit; + } +} + +void pfa_free(uintptr_t paddr, size_t num_pages) { + uintptr_t addr; + struct pfa_page *temp = (struct pfa_page*)PAGE_TMP_MAP; + for (size_t i = 0; i < num_pages; i++) { + addr = (i * PAGE_SIZE + paddr); + if (addr >= KSTART && addr < KEND) + continue; + if (addr == 0) + continue; + map_page(addr, PAGE_TMP_MAP, PD_PRES | PD_RW); + memset(PAGE_TMP_MAP, 1, 32); + temp->next = freelist.next; + freelist.next = addr; + unmap_page(PAGE_TMP_MAP); + } +} diff --git a/kernel/arch/x86/kernel/serial.c b/kernel/arch/x86/kernel/serial.c new file mode 100644 index 0000000..dc2a8bd --- /dev/null +++ b/kernel/arch/x86/kernel/serial.c @@ -0,0 +1,42 @@ +#include <kernel/serial.h> +#include <kernel/pic.h> +#include <libk/string.h> +#include <stddef.h> + +#define PORT 0x3f8 + +static inline int _serial_received(void) { + return inb(PORT + 5) & 1; +} + +static inline int _is_transmit_empty(void) { + return inb(PORT + 5) & 0x20; +} + +int serial_init(void) { + outb(PORT + 1, 0x00); + outb(PORT + 3, 0x80); + outb(PORT + 0, 0x03); + outb(PORT + 1, 0x00); + outb(PORT + 3, 0x03); + outb(PORT + 2, 0xC7); + outb(PORT + 4, 0x0B); + outb(PORT + 4, 0x1E); + outb(PORT + 0, 0xAE); + + if (inb(PORT + 0) != 0xAE) + return -1; + + outb(PORT + 4, 0x0F); + return 0; +} + +void serial_putchar(char c) { + while (_is_transmit_empty() == 0); + outb(PORT, c); +} + +char serial_getchar(void) { + while (_serial_received() == 0); + return inb(PORT); +} diff --git a/kernel/arch/x86/kernel/syscall.c b/kernel/arch/x86/kernel/syscall.c new file mode 100644 index 0000000..1fa73e9 --- /dev/null +++ b/kernel/arch/x86/kernel/syscall.c @@ -0,0 +1,25 @@ +#include <kernel/syscall.h> +#include <kernel/panic.h> +#include <libk/string.h> +#include <libk/io.h> +#include <stddef.h> + +void sys_read(struct isr_frame *frame) { +} + +void sys_write(struct isr_frame *frame) { +} + +void handle_syscall(struct isr_frame *frame) { + switch (frame->eax) { + case SYS_READ: + sys_read(frame); + break; + case SYS_WRITE: + sys_write(frame); + break; + default: + kprintf("Invalid system call number %d\n", frame->eax); + break; + } +} diff --git a/kernel/arch/x86/kernel/timer.c b/kernel/arch/x86/kernel/timer.c new file mode 100644 index 0000000..bd57cc2 --- /dev/null +++ b/kernel/arch/x86/kernel/timer.c @@ -0,0 +1,25 @@ +#include <kernel/timer.h> +#include <kernel/asm.h> +#include <kernel/pic.h> + +static uint32_t num_ticks = 0; + +void timer_handler(struct isr_frame *frame) { + num_ticks++; + if (num_ticks == 3) { + num_ticks = 0; + //schedule_next(); + } + pic_eoi(frame->isr_vector-32); +} + +void timer_init(void) { + disable_ints(); + int divisor = 1193182 / 100; + outb(0x43, 0x34); + outb(0x40, divisor && 0xFF); + outb(0x40, divisor && 0xFF00 >> 8); + enable_ints(); + + //register_isr_handler(32, timer_handler); +} |