diff --git a/include/kernel/elf.h b/include/kernel/elf.h new file mode 100644 index 0000000..b8b21a7 --- /dev/null +++ b/include/kernel/elf.h @@ -0,0 +1,46 @@ +#ifndef HAZEL_ELF_H_ +#define HAZEL_ELF_H_ + +#include + +#define EI_NIDENT 16 + +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; + +typedef struct { + uint8_t e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} elf_t; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} section_t; + +section_t *elf_find_section(elf_t *elf, const char *name); + +#endif diff --git a/include/kernel/kernel.h b/include/kernel/kernel.h index 9dd2495..e25809d 100644 --- a/include/kernel/kernel.h +++ b/include/kernel/kernel.h @@ -3,16 +3,11 @@ #include #include +#include #define cpu_relax asm volatile ("pause" ::) #define CHECK_FLAG(x, n) (x & (1< +#include + +typedef struct { + uint32_t eip; + uint32_t esp; + uint32_t cr3; + uint32_t *next; +} task_t; + +int task_init(task_t *task, elf_t *elf); +void schedule(void); + +#endif diff --git a/kernel/elf.c b/kernel/elf.c new file mode 100644 index 0000000..2b688ab --- /dev/null +++ b/kernel/elf.c @@ -0,0 +1,16 @@ +#include +#include + +section_t *elf_find_section(elf_t *elf, const char *name) { + section_t *str = (section_t *)((uint32_t)elf + elf->e_shoff + elf->e_shstrndx*elf->e_shentsize); + section_t *found = 0; + for (int i = 0; i < elf->e_shnum; i++) { + section_t *sec = (section_t *)((uint32_t)elf + elf->e_shoff + i*elf->e_shentsize); + const char *n = (char *)((uint32_t)elf + str->sh_offset + sec->sh_name); + if (!strcmp(n, name)) { + found = sec; + } + } + + return found; +} diff --git a/kernel/init.asm b/kernel/init.asm index a934bab..948cb4a 100644 --- a/kernel/init.asm +++ b/kernel/init.asm @@ -115,6 +115,31 @@ flush_tss: ltr [esp+4] ret +extern ctx +global task_switch +task_switch: + push ebx + push esi + push edi + push ebp + + mov esi, [ctx+28] + ; Return if only one process is running + mov eax, [esi+12] + cmp eax, 0 + je ret + ; Check if using same virtual memory + cmp [esi+8], [eax+8] + je .ret + mov ecx, [eax+8] + mov cr3, ecx +.ret: + pop ebp + pop edi + pop esi + pop ebx + ret + extern exception_handler %macro isr_err_stub 1 isr_stub_%+%1: diff --git a/kernel/kernel.c b/kernel/kernel.c index 0e37cb7..f8c12a9 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include kernel_ctx_t ctx = {0}; @@ -33,42 +35,41 @@ void sleep(int delay) { cpu_relax; } -int strcmp(const char *str1, const char *str2) { - while (*str1 && (*str1 == *str2)) { - str1++; - str2++; - } - return *(uint8_t *)str1 - *(uint8_t *)str2; -} - -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 - ctx.multi_mmap = (multi_mmap_t *)(info->memmapaddress + KERNEL_VMA); - ctx.multi_mmap_size = info->memmaplength; - - if (serial_port_init(COM1)) ctx.log_method = LOG_COM1; - LOG("Kernel log being sent to COM1\n"); - - 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); - +void idt_init() { for (int i = 0; i < 32; i++) { - idt_encode_entry(idt, i, isr_stub_table[i], GDT_SEGMENT_SELECTOR(1, 0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); + 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, 32, (uint32_t)pit_isr, GDT_SEGMENT_SELECTOR(1, 0), INT_GATE_32 | INT_RING0 | INT_PRESENT); + idt_encode_entry(idt, 32, (uint32_t)pit_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), INT_GATE_32 | INT_RING0 | 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"); + + 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); + + idt_init(); + + /* pic_remap(PIC_1_START, PIC_2_START); - //asm volatile ("sti" ::); - - //ctx.ticks = 0; - //pit_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; @@ -78,42 +79,24 @@ void kernel(multiboot_info_t *info) { gdt[5].granularity = (limit >> 16) & 0x0F; gdt[5].granularity |= 0x40; gdt[5].access = 0x89; - tss.ss0 = GDT_SEGMENT_SELECTOR(2, RING0); + tss.ss0 = GDT_SEGMENT_SELECTOR(GDT_KERNEL_DATA, RING0); uint32_t esp0 = 0; asm volatile ("mov %%esp, %0" : "=r" (esp0)); tss.esp0 = esp0; - tss.cs = GDT_SEGMENT_SELECTOR(3, RING3); - tss.ss = tss.ds = tss.es = tss.fs = tss.gs = GDT_SEGMENT_SELECTOR(4, RING3); + 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); - section_t *str = (section_t *)((uint32_t)elf + elf->e_shoff + elf->e_shstrndx*elf->e_shentsize); - section_t *text = 0; - for (int i = 0; i < elf->e_shnum; i++) { - section_t *sec = (section_t *)((uint32_t)elf + elf->e_shoff + i*elf->e_shentsize); - //LOG("Pingas: %d\n", elf->e_shstrndx); - const char *name = (char *)((uint32_t)elf + str->sh_offset + sec->sh_name); - if (!strcmp(name, ".text")) { - text = sec; - } - } + task_t task = {0}; + if (!task_init(&task, elf)) goto halt; - uint32_t elf_phys = (uint32_t)elf - KERNEL_VMA; - LOG("0x%08X\n", elf_phys); - uint32_t *elf_page_dir = mmap_find_first_free_block(); - uint32_t *elf_page_tab = mmap_find_first_free_block(); - elf_page_dir[768] = ((uint32_t)boot_page_tab - KERNEL_VMA) | 3; - elf_page_dir[PAGE_DIR_INDEX(elf->e_entry)] = ((uint32_t)elf_page_tab - KERNEL_VMA) | 7; - for (int i = 0; i < 1024; i++) { - elf_page_tab[i] = (elf_phys + 0x1000*i) | 7; - } + ctx.current_task = &task; + asm volatile ("mov %0, %%cr3" :: "r"(task.cr3)); - asm volatile ("mov %0, %%cr3" :: "r"((uint32_t)elf_page_dir - KERNEL_VMA)); - - uint32_t stack = (uint32_t)mmap_find_first_free_block(); - LOG("Switching to ring 3... EIP: 0x%08X ESP: 0x%08X\n", elf->e_entry+text->sh_offset, stack+0x1000); - jmp_user_mode(stack+0x1000, elf->e_entry+text->sh_offset); + 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 (;;) {} diff --git a/kernel/task.c b/kernel/task.c new file mode 100644 index 0000000..6dadeb1 --- /dev/null +++ b/kernel/task.c @@ -0,0 +1,39 @@ +#include +#include + +extern uint32_t boot_page_tab[1024]; +extern kernel_ctx_t ctx; + +int task_init(task_t *task, elf_t *elf) { + section_t *text = elf_find_section(elf, ".text"); + if (!text) return 0; + task->eip = elf->e_entry + text->sh_offset; + // Allocate a page for a stack + task->esp = (uint32_t)mmap_find_first_free_block() + 0x1000; + + uint32_t *page_dir = mmap_find_first_free_block(); + task->cr3 = (uint32_t)page_dir - KERNEL_VMA; + uint32_t *page_tab = mmap_find_first_free_block(); + for (int i = 0; i < 1024; i++) { + // Map kernel to 3GiB + if (i == 768) page_dir[i] = ((uint32_t)boot_page_tab - KERNEL_VMA) | 3; + // Map 3.4GiB-4GiB as non-present kernel entries + else if (i > 768) page_dir[i] = 4; + // Map remaining entries as non-present u/s + else page_dir[i] = 6; + } + // Map the ELF image to its specified entry + // This will cause problems if the ELF image is larger than 4 MiB so I need to fix this + page_dir[PAGE_DIR_INDEX(elf->e_entry)] = ((uint32_t)page_tab - KERNEL_VMA) | 7; + uint32_t elf_phys = (uint32_t)elf - KERNEL_VMA; + for (int i = 0; i < 1024; i++) { + page_tab[i] = (elf_phys + 0x1000*i) | 7; + } + + return 1; +} + +void schedule(void) { + // If there's only one task running + if (!ctx.current_task->next) return; +} diff --git a/lib/strcmp.h b/lib/strcmp.h new file mode 100644 index 0000000..ea1e6cd --- /dev/null +++ b/lib/strcmp.h @@ -0,0 +1,14 @@ +#ifndef HAZEL_STRCMP_H_ +#define HAZEL_STRCMP_H_ + +#include + +int strcmp(const char *str1, const char *str2) { + while (*str1 && (*str1 == *str2)) { + str1++; + str2++; + } + return *(uint8_t *)str1 - *(uint8_t *)str2; +} + +#endif