forked from PoliEcho-holding-org/kern
PREEMPTIVE MULTITASKING!!!!
This commit is contained in:
+15
-25
@@ -10,14 +10,14 @@ void gdt_reload(void) {
|
||||
__asm__ volatile (
|
||||
"cli\n"
|
||||
"lgdt (%0)\n"
|
||||
"ljmp $0x08, $1f\n"
|
||||
"1:\n"
|
||||
"movw $0x10, %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n"
|
||||
"movw %%ax, %%fs\n"
|
||||
"movw %%ax, %%gs\n"
|
||||
"movw %%ax, %%ss\n"
|
||||
"ljmp $0x08, $1f\n"
|
||||
"1:"
|
||||
:
|
||||
: "m" (gdtp)
|
||||
: "memory", "rax"
|
||||
@@ -26,38 +26,28 @@ void gdt_reload(void) {
|
||||
|
||||
void tss_reload(void) {
|
||||
__asm__ volatile ("ltr %0" : : "rm"(GDT_TSS));
|
||||
gdt[5].access |= 0x02;
|
||||
}
|
||||
|
||||
void tss_esp0(uint32_t esp0) { tss.esp0 = esp0; }
|
||||
|
||||
int gdt_init(void) {
|
||||
// Null descriptor (0)
|
||||
gdt[0] = GDT_DESC(0, 0, 0, 0);
|
||||
|
||||
// Kernel code (8)
|
||||
gdt[1] = GDT_DESC(0xfffff, 0, 0x9a, 0xc);
|
||||
|
||||
// Kernel data (16)
|
||||
gdt[2] = GDT_DESC(0xfffff, 0, 0x92, 0xc);
|
||||
|
||||
// User code (24)
|
||||
gdt[3] = GDT_DESC(0xfffff, 0, 0xfa, 0xc);
|
||||
|
||||
// User data (32)
|
||||
gdt[4] = GDT_DESC(0xfffff, 0, 0xf2, 0xc);
|
||||
|
||||
// TSS (40)
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
gdt[5] = GDT_DESC(sizeof(tss) - 1, (uint32_t)&tss, 0x89, 0x40);
|
||||
tss.iopb = sizeof(struct tss_pointer);
|
||||
tss.esp0 = __kernel_stack_top;
|
||||
tss.ss0 = GDT_KERNEL_DATA;
|
||||
|
||||
// GDT Pointer
|
||||
gdtp.limit = sizeof(gdt) - 1;
|
||||
gdtp.base = (uint32_t)&gdt;
|
||||
|
||||
// Setup TSS
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
tss.ss0 = GDT_KERNEL_DATA;
|
||||
tss.iopb = sizeof(struct tss_pointer);
|
||||
|
||||
// Load descriptors
|
||||
gdt[0] = GDT_DESC(0, 0, 0, 0); // Null descriptor
|
||||
gdt[1] = GDT_DESC(0xFFFFFFFF, 0, 0x9A, 0xC0); // Kernel code
|
||||
gdt[2] = GDT_DESC(0xFFFFFFFF, 0, 0x92, 0xC0); // Kernel data
|
||||
gdt[3] = GDT_DESC(0xFFFFFFFF, 0, 0xFA, 0xC0); // User code
|
||||
gdt[4] = GDT_DESC(0xFFFFFFFF, 0, 0xF2, 0xC0); // User data
|
||||
gdt[5] = GDT_DESC(sizeof(tss) - 1, (uint32_t)&tss, 0x89, 0);
|
||||
|
||||
gdt_reload();
|
||||
tss_reload();
|
||||
|
||||
|
||||
+2
-1
@@ -89,12 +89,13 @@ void isr_send_eoi(uint8_t irq) {
|
||||
int isr_handle_interrupt(struct isr_int_frame iframe) {
|
||||
if (iframe.interrupt < 32) {
|
||||
// ISRs 0-31 - Exceptions
|
||||
if (iframe.error) debugf("[kernel] Error code: 0x%08x\n", iframe.error);
|
||||
panic(exceptions[iframe.interrupt]);
|
||||
} else if (iframe.interrupt >= 32 && iframe.interrupt < 48) {
|
||||
// ISRs 32-47 - Hardware interrupts
|
||||
uint8_t irq = iframe.interrupt - 32;
|
||||
if (irq_handlers[irq]) irq_handlers[irq](&iframe);
|
||||
isr_send_eoi(irq);
|
||||
if (irq_handlers[irq]) irq_handlers[irq](&iframe);
|
||||
} else if (iframe.interrupt == 128) {
|
||||
// ISR 128 - System call
|
||||
return syscall_handler(&iframe);
|
||||
|
||||
+2
-2
@@ -30,14 +30,14 @@ isr_common:
|
||||
[extern isr_handle_interrupt]
|
||||
call isr_handle_interrupt
|
||||
[global isr_return]
|
||||
isr_return: ; Also used by task switching
|
||||
isr_return: ; Also used by a newly created task
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popad
|
||||
add esp, 8 ; Pop interupt number and error code
|
||||
iretd ; Pop CS, EIP & EFLAGS (Also SS & ESP if it's from userspace)
|
||||
iret ; Pop CS, EIP & EFLAGS (Also SS & ESP if it's from userspace)
|
||||
|
||||
%macro ISR_WITH_ERRNO 1
|
||||
isr%1:
|
||||
|
||||
+30
-4
@@ -10,6 +10,8 @@
|
||||
#include <pmm.h>
|
||||
#include <tty.h>
|
||||
|
||||
void test(void);
|
||||
|
||||
__noreturn
|
||||
void kmain(void* ptr, uint32_t magic) {
|
||||
if (boot_init_mb1(ptr, magic) != 0) panic("Unsupported bootloader.");
|
||||
@@ -20,6 +22,8 @@ void kmain(void* ptr, uint32_t magic) {
|
||||
|
||||
// System init
|
||||
if (gdt_init() != 0) panic("Failed to initalize GDT.");
|
||||
debugf("[gdt] Segment selectors: NULL: 0x%04x, KCODE: 0x%04x, KDATA: 0x%04x, UCODE: 0x%04x, UDATA: 0x%04x, TSS: 0x%04x\n",
|
||||
GDT_NULL, GDT_KERNEL_CODE, GDT_KERNEL_DATA, GDT_USER_CODE, GDT_USER_DATA, GDT_TSS);
|
||||
if (isr_init() != 0) panic("Failed to initalize ISRs.");
|
||||
if (pag_init() != 0) panic("Failed to initalize Paging.");
|
||||
|
||||
@@ -34,14 +38,36 @@ void kmain(void* ptr, uint32_t magic) {
|
||||
if (timer_init() != 0) panic("Failed to initialize timer.");
|
||||
if (task_init() != 0) panic("Failed to initialize tasking.");
|
||||
|
||||
// TODO: Scheduler
|
||||
// Create a temporary test task
|
||||
task_create(task_create_id(), (uint32_t)test, 1, pag_get_pagedir(), 0, NULL);
|
||||
|
||||
size_t delay = 0;
|
||||
while (1) {
|
||||
delay++;
|
||||
|
||||
if (delay < 0x1FFFFFF) continue;
|
||||
delay = 0;
|
||||
|
||||
tty_puts("[kernel] Hello!\n");
|
||||
}
|
||||
|
||||
// TODO: Syscalls
|
||||
// TODO: Interprocess communication
|
||||
// TODO: Tasking
|
||||
// TODO: Load & run /sbin/init
|
||||
|
||||
while (1);
|
||||
|
||||
panic("kmain() reached end.");
|
||||
}
|
||||
|
||||
// An imaginary second task
|
||||
void test(void) {
|
||||
size_t delay = 0;
|
||||
while (1) {
|
||||
delay++;
|
||||
|
||||
if (delay < 0x2FFFFFF) continue;
|
||||
delay = 0;
|
||||
|
||||
tty_puts("[test] Hello!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <kernel.h>
|
||||
#include <task.h>
|
||||
#include <gdt.h>
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
void schedule(void) {
|
||||
if (task_first == NULL) return;
|
||||
|
||||
struct task* next = task_current->next;
|
||||
if (next == NULL) next = task_first;
|
||||
|
||||
while (next->state != TASK_STATE_READY) {
|
||||
next = next->next;
|
||||
if (next == NULL) next = task_first;
|
||||
}
|
||||
|
||||
struct task* old = task_current;
|
||||
task_current = next;
|
||||
|
||||
tss_esp0(next->kstack_bottom);
|
||||
|
||||
// NOTE: Might not return
|
||||
task_switch(old, next);
|
||||
}
|
||||
|
||||
+8
-5
@@ -31,7 +31,7 @@ int task_init(void) {
|
||||
}
|
||||
|
||||
void task_create(size_t id, uint32_t eip, int kernel_task, uint32_t* pagedir, int argc, char** argv) {
|
||||
__asm__ volatile ("cli"); // Make sure we don't get interrupted
|
||||
__asm__ volatile ("cli"); // Make sure we don't get interrupted
|
||||
|
||||
uint32_t kstack = (uint32_t)kmalloc(0x1000 - 16) + (0x1000 - 16);
|
||||
uint8_t* kesp = (uint8_t*)kstack;
|
||||
@@ -55,7 +55,7 @@ void task_create(size_t id, uint32_t eip, int kernel_task, uint32_t* pagedir, in
|
||||
trap->eflags = 0x200; // Enable interrupts
|
||||
trap->eip = eip;
|
||||
|
||||
kesp -= sizeof(struct isr_int_frame);
|
||||
kesp -= sizeof(struct task_switch_ctx);
|
||||
struct task_switch_ctx* ctx = (struct task_switch_ctx*)kesp;
|
||||
ctx->edi = 0;
|
||||
ctx->esi = 0;
|
||||
@@ -82,6 +82,9 @@ void task_create(size_t id, uint32_t eip, int kernel_task, uint32_t* pagedir, in
|
||||
new->heap_start = USER_HEAP;
|
||||
new->heap_end = USER_HEAP;
|
||||
|
||||
debugf("[task] NEW! Task #%d - EIP = 0x%08x, ESP = 0x%08x%s\n",
|
||||
id, eip, kesp, kernel_task ? " (kernel)" : "");
|
||||
|
||||
// We don't need to setup a stack frame
|
||||
if (kernel_task) {
|
||||
__asm__ volatile ("sti");
|
||||
@@ -91,7 +94,7 @@ void task_create(size_t id, uint32_t eip, int kernel_task, uint32_t* pagedir, in
|
||||
void* old_pagedir = pag_get_pagedir();
|
||||
pag_set_pagedir(new->pagedir);
|
||||
|
||||
// Setup argc, argv & environ
|
||||
// Setup argc, argv
|
||||
size_t arg_len = 0;
|
||||
for (int i = 0; i < argc; i++) arg_len += strlen(argv[i]) + 1;
|
||||
size_t page_count = dceil(4 + (argc * 4) + 10 + arg_len, PAGE_SIZE);
|
||||
@@ -186,7 +189,7 @@ void task_set_user_heap(struct task* task, size_t heap_end) {
|
||||
else if (new_page_top > old_page_top) { // Grow
|
||||
int num = new_page_top - old_page_top;
|
||||
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
uint32_t paddr = (uint32_t)pmm_alloc();
|
||||
if (paddr == 0) {
|
||||
debugf("[task] Task %d tried to grow heap too much.\n", task->id);
|
||||
@@ -199,7 +202,7 @@ void task_set_user_heap(struct task* task, size_t heap_end) {
|
||||
} else { // Shrink
|
||||
int num = old_page_top - new_page_top;
|
||||
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
uint32_t vaddr = old_page_top * PAGE_SIZE + i * PAGE_SIZE;
|
||||
uint32_t paddr = pag_virt_to_phys(vaddr);
|
||||
pmm_free(paddr);
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ bits 32
|
||||
global task_switch
|
||||
task_switch:
|
||||
mov eax, [esp + 4] ; eax = struct task* old
|
||||
mov edx, [esp + 8] ; ebx = struct task* nex
|
||||
|
||||
mov edx, [esp + 8] ; ebx = struct task* new
|
||||
|
||||
;; Push registers that weren't pushed by the CDECL call
|
||||
push ebp
|
||||
push ebx
|
||||
|
||||
+5
-2
@@ -1,5 +1,6 @@
|
||||
#include <kernel.h>
|
||||
#include <system.h>
|
||||
#include <sched.h>
|
||||
#include <isr.h>
|
||||
#include <tty.h>
|
||||
|
||||
@@ -19,7 +20,7 @@ void timer_wait(size_t t) {
|
||||
|
||||
int pit_init(void) {
|
||||
isr_register(0, pit_handler);
|
||||
pit_phase(0, 2, 1000);
|
||||
pit_phase(0, 2, TIMER_FREQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -39,8 +40,10 @@ void pit_phase(uint8_t ch, uint8_t mode, uint32_t hz) {
|
||||
}
|
||||
|
||||
void pit_handler(struct isr_int_frame* iframe) {
|
||||
(void)iframe; // We must take it as an argument even if we don't use it
|
||||
timer_ticks++;
|
||||
|
||||
if (timer_ticks % 1000 == 0) tty_puts(".");
|
||||
// TODO: This assumes the timer is at 1000 Hz
|
||||
if (timer_ticks % SCHED_QUANTUM == 0) schedule();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user