#include #include #include #include #include #include #include #include #include #include #include #include #include #include kernel_ctx_t ctx = {0}; struct idt_entry idt[256] = {0}; struct idtr idtr = {0}; tss_t tss = {0}; extern uint32_t isr_stub_table[32]; extern void pit_isr(void); extern void ps2_isr(void); extern void jmp_user_mode(uint32_t esp, uint32_t eip); extern void flush_tss(uint32_t segment_selector); extern void task_switch(task_t *task); extern void syscall(void); extern void syscall_isr(void); extern gdt_t gdt[6]; extern uint32_t boot_page_dir[1024]; extern uint32_t boot_page_tab[1024]; #define FD_STDIN 0 #define FD_STDOUT 1 void syscall_write(stack_frame_t r) { uint32_t fd = r.edi; uint8_t *buf = (uint8_t *)r.esi; int len = r.edx; if (fd == FD_STDOUT) { for (int i = 0; i < len; i++) { vga_putc(buf[i]); } } } void syscall_read(stack_frame_t r) { uint32_t fd = r.edi; uint8_t *buf = (uint8_t *)r.esi; uint32_t len = r.edx; if (fd == FD_STDOUT) { // Not yet } else if (fd == FD_STDIN) { // for some reason interrupts are disabled asm volatile ("sti" ::); while (ctx.current_task->stdin[ctx.current_task->stdin_len - 1] != '\n') cpu_relax; if (ctx.current_task->stdin_len > 0) ctx.current_task->stdin[--ctx.current_task->stdin_len] = 0; memcpy(buf, ctx.current_task->stdin, len); for (int i = 0; i < 0x1000; i++) ctx.current_task->stdin[i] = 0; ctx.current_task->stdin_len = 0; } } void syscall_reboot(stack_frame_t r) { (void)r; ps2_reboot; } void syscall_uptime(stack_frame_t r) { uint32_t *low = (uint32_t *)r.esi; uint32_t *high = (uint32_t *)r.edi; *low = (uint32_t)ctx.ticks; *high = (uint32_t)(ctx.ticks >> 32); } void exception_handler(int_stack_frame_t r) { LOG("Exception 0x%X (0x%X) has occurred\nEAX: 0x%08X\nECX: 0x%08X\nEDX: 0x%08X\nEBX: 0x%08X\nESI: 0x%08X\nEDI: 0x%08X\nEBP: 0x%08X\nESP: 0x%08X\n", r.int_no, r.err_code, r.eax, r.ecx, r.edx, r.ebx, r.esi, r.edi, r.ebp, r.esp+24); LOG("\nEIP: 0x%08X\nCS: 0x%08X\nEFLAGS: 0x%08X\n", r.eip, r.cs, r.eflags); // Page fault if (r.int_no == 0xe) { uint32_t cr2 = 0; asm volatile ("mov %%cr2, %0" : "=r" (cr2)); LOG("CR2: 0x%08X\n", cr2) uint32_t cr3 = 0; asm volatile ("mov %%cr3, %0" : "=r" (cr3)); uint32_t *page_dir = (uint32_t *)(KERNEL_VMA + cr3); if ((page_dir[PAGE_DIR_INDEX(cr2)] & 0xFFFFF000) == 0) { LOG("Creating new page table\n"); uint32_t *page_tab = mmap_find_first_free_block(); if (!page_tab) for (;;) {} page_tab[PAGE_TAB_INDEX(cr2)] = (cr2 & 0xFFFFF000) | 7; page_dir[PAGE_DIR_INDEX(cr2)] = ((uint32_t)page_tab - KERNEL_VMA) | 7; } else { uint32_t *page_tab = (uint32_t *)(KERNEL_VMA + (page_dir[PAGE_DIR_INDEX(cr2)] & 0xFFFFF000)); page_tab[PAGE_TAB_INDEX(cr2)] = (cr2 & 0xFFFFF000) | 7; } } } void sleep(int delay) { uint64_t end = ctx.ticks + delay; while (ctx.ticks < end) cpu_relax; } void idt_init(void) { for (int i = 0; i < 32; i++) { idt_encode_entry(idt, i, isr_stub_table[i], GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); } idt_encode_entry(idt, 0x20, (uint32_t)pit_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); idt_encode_entry(idt, 0x21, (uint32_t)ps2_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); idt_encode_entry(idt, 0x80, (uint32_t)syscall_isr, GDT_SEGMENT_SELECTOR(GDT_USER_CODE, RING3), TRAP_GATE_32 | INT_RING3 | INT_PRESENT); idtr.size = (sizeof(struct idt_entry) * 256) - 1; idtr.base = (uint32_t) idt; asm volatile ("lidt %0" :: "m"(idtr)); } void kernel(multiboot_info_t *info) { if (!CHECK_FLAG(info->flags, 3)) goto halt; // Modules if (!CHECK_FLAG(info->flags, 6)) goto halt; // Memory map if (!CHECK_FLAG(info->flags, 12)) goto halt; // VBE data if (serial_port_init(COM1)) ctx.log_method = LOG_COM1; LOG("Kernel log being sent to COM1\n"); idt_init(); ctx.multi_mmap = (multi_mmap_t *)(info->memmapaddress + KERNEL_VMA); ctx.multi_mmap_size = info->memmaplength; if (!mmap_init()) goto halt; LOG("%d bytes of RAM detected\nCreated a %d byte large physical memory map at 0x%08X\n", ctx.mmap_size*BLOCK_SIZE*8, ctx.mmap_size, (uint32_t)ctx.mmap); clear_screen(); acpi_init(); for (int i = 0; i < 256; i++) { for (int j = 0; j < 32; j++) { for (int k = 0; k < 8; k++) { uint16_t w = pci_read_cfg(i, j, k, 0xA); uint8_t class = (uint8_t)(w >> 8); uint8_t subclass = (uint8_t)w; if (class == 0xFF) continue; LOG("PCI Class: %04X | Subclass: %04X\n", class, subclass); } } } pic_remap(PIC_1_START, PIC_2_START); ps2_init(); asm volatile ("sti" ::); ctx.ticks = 0; pit_init(); // Setup TSS uint32_t base = (uint32_t)&tss; uint32_t limit = base + sizeof(tss_t); gdt[5].base_low = base & 0xFFFF; gdt[5].base_middle = (base >> 16) & 0xFF; gdt[5].base_high = (base >> 24) & 0xFF; gdt[5].limit_low = limit & 0xFFFF; gdt[5].granularity = (limit >> 16) & 0x0F; gdt[5].granularity |= 0x40; gdt[5].access = 0x89; tss.ss0 = GDT_SEGMENT_SELECTOR(GDT_KERNEL_DATA, RING0); uint32_t esp0 = 0; asm volatile ("mov %%esp, %0" : "=r" (esp0)); // Questionable tss.esp0 = esp0; tss.cs = GDT_SEGMENT_SELECTOR(GDT_USER_CODE, RING3); tss.ss = tss.ds = tss.es = tss.fs = tss.gs = GDT_SEGMENT_SELECTOR(GDT_USER_DATA, RING3); flush_tss(GDT_SEGMENT_SELECTOR(5, RING3)); multi_mod_t *init = (multi_mod_t *)(info->moduleaddress + KERNEL_VMA); elf_t *elf = (elf_t *)(init->mod_start+KERNEL_VMA); task_t task = {0}; if (!task_init(&task, elf)) goto halt; ctx.current_task = &task; asm volatile ("mov %0, %%cr3" :: "r"(task.cr3)); // Set the ring0 CS asm volatile ( "movl $0x174, %%ecx \n\t" "movl %0, %%eax \n\t" "xor %%edx, %%edx \n\t" "wrmsr" : : "r"(GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0)) : "eax", "ecx", "edx" ); // Set the ring0 stack uint32_t *k_stack = mmap_find_first_free_block(); asm volatile ( "movl $0x175, %%ecx \n\t" "movl %0, %%eax \n\t" "xor %%edx, %%edx \n\t" "wrmsr" : : "r"((uint32_t)k_stack + 0x1000) : "eax", "ecx", "edx" ); // Set the ring0 syscall entry asm volatile ( "movl $0x176, %%ecx \n\t" "movl %0, %%eax \n\t" "xor %%edx, %%edx \n\t" "wrmsr" : : "r"(syscall) : "eax", "ecx", "edx" ); LOG("Switching to ring 3... EIP: 0x%08X ESP: 0x%08X\n", task.eip, task.esp); jmp_user_mode(task.esp, task.eip); halt: for (;;) {} }