PREEMPTIVE MULTITASKING!!!!

This commit is contained in:
2025-05-06 19:29:35 +02:00
parent a48fa362d0
commit c646404cf0
14 changed files with 215 additions and 103 deletions
+15 -25
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
}
}
+26
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
}