IMPLEMENTED TASKS!

This commit is contained in:
2025-04-30 18:27:18 +02:00
parent f4b10746d6
commit a48fa362d0
10 changed files with 404 additions and 43 deletions
+29 -25
View File
@@ -3,37 +3,41 @@
isr_common:
;; Push registers to the int_frame_t struct
push eax
push gs
push fs
push es
pushad
;; push eax
;; push ecx
;; push edx
;; push ebx
;; push esp
;; push ebp
;; push esi
;; push edi
push ds
push ebp
push edi
push esi
push edx
push ecx
push es
push fs
push gs
;; Load kernel data segment
push ebx
push esp
mov bx, 0x10
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
pop ebx
[extern isr_handle_interrupt]
call isr_handle_interrupt
isr_return:
add esp, 4 ; Keep ESP
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
pop ds
pop es
pop fs
[global isr_return]
isr_return: ; Also used by task switching
pop gs
add esp, 4 ; Keep EAX
add esp, 8 ; Pop interupt number and error code
iretd ; Pop CS, EIP & EFLAGS (Also SS & ESP if it's from userspace)
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)
%macro ISR_WITH_ERRNO 1
isr%1:
+2
View File
@@ -4,6 +4,7 @@
#include <paging.h>
#include <serial.h>
#include <timer.h>
#include <task.h>
#include <gdt.h>
#include <isr.h>
#include <pmm.h>
@@ -31,6 +32,7 @@ void kmain(void* ptr, uint32_t magic) {
tty_puts("kern.\n\n");
if (timer_init() != 0) panic("Failed to initialize timer.");
if (task_init() != 0) panic("Failed to initialize tasking.");
// TODO: Scheduler
// TODO: Syscalls
+7 -7
View File
@@ -68,7 +68,7 @@ void pag_map(uint32_t vaddr, uint32_t paddr, uint32_t flags) {
// Allocate a pagetab if it didn't exist
if (!(pagedir[pdi] & PAGE_FLAG_PRESENT)) {
uint32_t tabaddr = pmm_bitmap.ready ? (uint32_t)pmm_alloc() : pag_temp_frame();
uint32_t tabaddr = pmm_bitmap.ready ? pmm_alloc() : pag_temp_frame();
pagedir[pdi] = tabaddr |
PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE | PAGE_FLAG_OWNER | flags;
@@ -125,14 +125,14 @@ uint32_t pag_umap(uint32_t vaddr) {
uint32_t pde = pagedir[pdi];
if (remove && pde & PAGE_FLAG_OWNER) {
uint32_t tabaddr = PHYS_ADDR(pde);
pmm_free((void*)tabaddr);
pmm_free(tabaddr);
pagedir[pdi] = 0;
}
invalidate(vaddr);
// Free the page frame
if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte));
if (pte & PAGE_FLAG_OWNER) pmm_free(PHYS_ADDR(pte));
if (prevpd != NULL) {
pag_sync_pagedir(); // Sync it to other pagedirs
@@ -142,13 +142,13 @@ uint32_t pag_umap(uint32_t vaddr) {
return pte;
}
void* pag_virt_to_phys(uint32_t vaddr) {
uint32_t pag_virt_to_phys(uint32_t vaddr) {
uint32_t pdi = vaddr >> 22;
uint32_t pti = vaddr >> 12 & 0x3FF;
uint32_t* pagetab = PAGETAB(pdi);
return (void*)((pagetab[pti] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF));
return (pagetab[pti] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF);
}
uint32_t* pag_get_pagedir() {
@@ -224,11 +224,11 @@ void pag_free_pagedir(uint32_t* pagedir) {
for (size_t j = 0; j < 1024; j++) {
uint32_t pte = pagetab[j];
if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte));
if (pte & PAGE_FLAG_OWNER) pmm_free(PHYS_ADDR(pte));
}
memset(pagetab, 0, PAGE_SIZE);
if (pde & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pde));
if (pde & PAGE_FLAG_OWNER) pmm_free(PHYS_ADDR(pde));
pd[i] = 0;
}
+6 -6
View File
@@ -83,19 +83,19 @@ int pmm_init(void) {
return 0;
}
void* pmm_alloc(void) {
if (pmm_bitmap.blocks - pmm_bitmap.used == 0) return NULL;
uint32_t pmm_alloc(void) {
if (pmm_bitmap.blocks - pmm_bitmap.used == 0) return 0;
size_t base = bmap_get_area(&pmm_bitmap, 1, 0);
if (base == BMAP_NOT_FOUND) return NULL;
if (base == BMAP_NOT_FOUND) return 0;
bmap_set(&pmm_bitmap, base, 1);
return bmap_ptr(&pmm_bitmap, base);
return (uint32_t)bmap_ptr(&pmm_bitmap, base);
}
void pmm_free(void* page) {
size_t base = (size_t)page / BLOCK_SIZE;
void pmm_free(uint32_t page) {
size_t base = page / BLOCK_SIZE;
bmap_set_area(&pmm_bitmap, base, 1, 0);
bmap_set(&pmm_bitmap, 0, 1);
}
+247
View File
@@ -0,0 +1,247 @@
#include <kmalloc.h>
#include <kernel.h>
#include <paging.h>
#include <string.h>
#include <gdt.h>
#include <isr.h>
#include <pmm.h>
#include <task.h>
struct task* task_first;
struct task* task_dummy;
struct task* task_current;
int task_init(void) {
task_first = kzalloc(sizeof(*task_first));
task_dummy = kzalloc(sizeof(*task_dummy));
if (task_first == NULL || task_dummy == NULL) return 1;
// The first task is what's running right now @~@
task_current = task_first;
task_current->id = TASK_KERNEL;
task_current->state = TASK_STATE_READY;
task_current->pagedir = pag_get_pagedir();
task_current->kernel_task = 1;
debugf("[task] Multitasking initiated.\n");
return 0;
}
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
uint32_t kstack = (uint32_t)kmalloc(0x1000 - 16) + (0x1000 - 16);
uint8_t* kesp = (uint8_t*)kstack;
kesp -= sizeof(struct isr_int_frame);
struct isr_int_frame* trap = (struct isr_int_frame*)kesp;
memset(trap, 0, sizeof(*trap));
uint16_t codesel = kernel_task ? GDT_KERNEL_CODE : GDT_USER_CODE;
uint16_t datasel = kernel_task ? GDT_KERNEL_DATA : GDT_USER_DATA;
trap->cs = codesel;
trap->ds = datasel;
trap->es = datasel;
trap->fs = datasel;
trap->gs = datasel;
trap->user_ss = datasel;
trap->user_esp = USER_STACK;
trap->eflags = 0x200; // Enable interrupts
trap->eip = eip;
kesp -= sizeof(struct isr_int_frame);
struct task_switch_ctx* ctx = (struct task_switch_ctx*)kesp;
ctx->edi = 0;
ctx->esi = 0;
ctx->ebx = 0;
ctx->ebp = 0;
ctx->eip = (uint32_t)isr_return;
struct task* current = task_first;
while (current != NULL) {
if (current->next == NULL) break;
current = current->next;
}
struct task* new = kzalloc(sizeof(*new));
current->next = new;
new->kstack_bottom = kstack;
new->kstack_pointer = (size_t)kesp;
new->id = id;
new->kernel_task = kernel_task;
new->state = TASK_STATE_READY;
new->pagedir = pagedir;
new->heap_start = USER_HEAP;
new->heap_end = USER_HEAP;
// We don't need to setup a stack frame
if (kernel_task) {
__asm__ volatile ("sti");
return;
}
void* old_pagedir = pag_get_pagedir();
pag_set_pagedir(new->pagedir);
// Setup argc, argv & environ
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);
for (size_t i = 0; i < page_count; i++) {
uint32_t paddr = pmm_alloc();
if (paddr == 0) { // Not enough memory
// TODO: Do pmm_free() for each page
kfree(new);
kfree((void*)kstack);
pag_set_pagedir(old_pagedir);
return;
}
pag_map(USER_STACK + i * PAGE_SIZE, (uint32_t)paddr, 0);
}
int* argc_ptr = (int*)USER_STACK;
char** argv_ptr = (char**)(USER_STACK + 4);
*argc_ptr = argc;
size_t cur = 0;
for (int i = 0; i < argc; i++) {
size_t len = strlen(argv[i]);
char* ptr = (char*)((size_t)argv_ptr + argc * 4 + 4 + cur);
memcpy(ptr, argv[i], len);
ptr[len] = '\0';
argv_ptr[i] = ptr;
cur += len + 1;
}
pag_set_pagedir(old_pagedir);
}
void task_kill(size_t id) {
__asm__ volatile ("cli");
struct task* current = task_first;
while (current != NULL) {
if (current->next && current->next->id == id) break;
current = current->next;
}
struct task* task = current->next;
if (task == NULL || task->state == TASK_STATE_DEAD) return;
current->next = task->next;
void* kstack = (void*)(task->kstack_bottom + 0x1000 - 16);
kfree(kstack);
uint32_t* old_pagedir = pag_get_pagedir();
pag_set_pagedir(task->pagedir);
size_t heap_start = dceil(task->heap_start, PAGE_SIZE);
size_t heap_end = dceil(task->heap_end, PAGE_SIZE);
if (heap_end > heap_start) {
size_t num = heap_end - heap_start;
for (size_t i = 0; i < num; i++) {
uint32_t vaddr = heap_start * PAGE_SIZE + i * PAGE_SIZE;
uint32_t paddr = pag_virt_to_phys(vaddr);
pmm_free(paddr);
}
}
pag_set_pagedir(old_pagedir);
pag_free_pagedir(task->pagedir);
// Workaround so we don't free a task we're in
if (task_current == task) {
memset(task_dummy, 0, sizeof(*task_dummy));
task_current = task_dummy;
}
kfree(task);
// schedule();
__asm__ volatile ("sti");
}
void task_set_user_heap(struct task* task, size_t heap_end) {
if (heap_end <= task->heap_start) {
debugf("[task] Task %d tried to shrink heap bellow 0.\n", task->id);
task_kill(task->id);
return;
}
int old_page_top = dceil(task->heap_end, PAGE_SIZE);
int new_page_top = dceil(heap_end, PAGE_SIZE);
if (new_page_top == old_page_top) return;
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++) {
uint32_t paddr = (uint32_t)pmm_alloc();
if (paddr == 0) {
debugf("[task] Task %d tried to grow heap too much.\n", task->id);
task_kill(task->id);
}
uint32_t vaddr = old_page_top * PAGE_SIZE + i * PAGE_SIZE;
pag_map(vaddr, paddr, PAGE_FLAG_USER);
memset((void*)vaddr, 0, PAGE_SIZE);
}
} else { // Shrink
int num = old_page_top - new_page_top;
for (size_t 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);
pag_umap(vaddr);
}
}
task->heap_end = heap_end;
}
struct task* task_get(size_t id) {
struct task* find = task_first;
while (find != NULL) {
if (find->id == id) break;
find = find->next;
}
return find;
}
uint8_t task_get_state(size_t id) {
struct task* t = task_get(id);
if (t == NULL) return TASK_STATE_DEAD;
return t->state;
}
void task_set_state(size_t id, uint8_t state) {
struct task* t = task_get(id);
if (t == NULL) return;
t->state = state;
}
size_t task_create_id(void) {
struct task* current = task_first;
size_t max = current->id;
current = current->next;
while (current != NULL) {
if (max < current->id) max = current->id;
current = current->next;
}
return max + 1;
}
+35
View File
@@ -0,0 +1,35 @@
bits 32
;; Prototype:
;; void switch_context(struct task* old, struct task* new);
;; Description:
;; Pushes register state onto the old tasks kstack and pops the new state.
global task_switch
task_switch:
mov eax, [esp + 4] ; eax = struct task* old
mov edx, [esp + 8] ; ebx = struct task* nex
;; Push registers that weren't pushed by the CDECL call
push ebp
push ebx
push esi
push edi
;; Swap the stack pointers
mov [eax + 4], esp ; old->kstack_pointer = ESP
mov esp, [edx + 4] ; ESP = new->kstack_pointer
;; Change the pagedir
mov eax, [edx + 12] ; EAX = new->pagedir
sub eax, 0xC0000000 ; Convert to physical address
mov cr3, eax
;; Pop register that weren't pushed by the CDECL call
pop edi
pop esi
pop ebx
pop ebp
;; This return will pop task_switch_ctx.eip
ret