implement basic multitasking

This commit is contained in:
2025-03-31 14:51:33 +03:00
parent 10eb4687f0
commit 9381b4cdb7
6 changed files with 243 additions and 1 deletions
+7 -1
View File
@@ -1,5 +1,5 @@
# Define the object files # Define the object files
OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o bin/keyboard.o bin/paging.o bin/fat.o OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o bin/keyboard.o bin/paging.o bin/fat.o bin/task.o bin/switch.o
# Define the compiler and assembler # Define the compiler and assembler
CC = gcc -D__is_katauos CC = gcc -D__is_katauos
@@ -96,6 +96,12 @@ bin/paging.o: src/paging.c
bin/fat.o: src/fat.c bin/fat.o: src/fat.c
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
bin/switch.o: src/switch.asm
$(AS) $(ASFLAGS) $< -o $@
bin/task.o: src/task.c
$(CC) $(CFLAGS) -c $< -o $@
clean: clean:
rm -rf bin/ rm -rf bin/
rm -f $(OUTPUT) rm -f $(OUTPUT)
+32
View File
@@ -0,0 +1,32 @@
#ifndef TASK_H
#define TASK_H
#include <stdint.h>
typedef enum TaskState
{
Ready,
Running,
Waiting,
Terminated
} TaskState;
typedef void (*EntryPoint)(void);
typedef struct Process
{
uint32_t pid; // Process ID
TaskState state; // Process state
uintptr_t programCounter; // Program Counter
uintptr_t* stackBase; // Top of the stack
uintptr_t* stackPointer; // Stack Pointer
uint32_t flags; // Status/Flags register
struct Process* next; // Pointer to the next task in the list
} Process;
Process* task_create(EntryPoint func);
void scheduler_init();
void schedule();
void scheduler_lock();
void scheduler_unlock();
#endif
+5
View File
@@ -4,6 +4,7 @@
#include "../include/pic.h" #include "../include/pic.h"
#include "../include/pit.h" #include "../include/pit.h"
#include "../include/keyboard.h" #include "../include/keyboard.h"
#include "../include/task.h"
#include <stddef.h> #include <stddef.h>
@@ -75,6 +76,10 @@ __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame)
{ {
pit_init(100); pit_init(100);
pic_end_int(0x0); pic_end_int(0x0);
scheduler_lock();
schedule();
scheduler_unlock();
} }
__attribute__((interrupt)) void isr_custom(struct interrupt_frame *frame) __attribute__((interrupt)) void isr_custom(struct interrupt_frame *frame)
+2
View File
@@ -8,6 +8,7 @@
#include "../include/pit.h" #include "../include/pit.h"
#include "../include/paging.h" #include "../include/paging.h"
#include "../include/fat.h" #include "../include/fat.h"
#include "../include/task.h"
#include <stdint.h> #include <stdint.h>
@@ -151,6 +152,7 @@ void kmain()
heap_init(); heap_init();
printf("after heap_init\n"); printf("after heap_init\n");
__asm__ __volatile__ ("sti"); __asm__ __volatile__ ("sti");
scheduler_init();
printf("Kernel init sequence completed\n"); printf("Kernel init sequence completed\n");
char yooo[256] = "heheh"; char yooo[256] = "heheh";
+96
View File
@@ -0,0 +1,96 @@
extern current
global switchProcess
struc PCB
.PID resd 1 ; Offset: 0
.STATE resd 1 ; Offset: 4
.PROGRAM_COUNTER resd 1 ; Offset: 8
.STACK_BASE resd 1 ; Offset: 12
.STACK_POINTER resd 1 ; Offset: 16
.FLAGS resd 1 ; Offset: 20
.NEXT resd 1 ; Offset: 24
endstruc
section .text
; void switchProcess(Process* next)
switchProcess:
; __________Stack___________
; |------------------------|
; | Return Address (EIP) | +0
; |------------------------|
; | Process* next | +4
; |------------------------|
; Push volatile registers (per the 32-bit System V ABI)
push ebx
push esi
push edi
push ebp
; __________Stack___________
; |------------------------|
; | EBP | +0
; |------------------------|
; | EDI | +4
; |------------------------|
; | ESI | +8
; |------------------------|
; | EBX | +12
; |-------- ---------------|
; | Return Address (EIP) | +16
; |------------------------|
; | Process* next | +20
; |------------------------|
; Save current process' state
mov edi, [current]
; EDI now contains the pointer to [Process* current]
; |-----|
; | EDI | <== [Process* current]
; |-----|
; Set [current->PCB.STACK_POINTER] to the value in ESP
; Process* current->PCB.STACK_POINTER <== ESP
mov [edi + PCB.STACK_POINTER], esp
; Load next process' state
; ESP has been decremented by 16, so instead of +4,
; we need to do +20. 4 pushes, 1 return address, 4
; bytes each.
mov esi, [esp + 20]
; ESI now contains the pointer to [Process* next]
; __________Stack___________
; |------------------------|
; | Return Address (EIP) | +16
; |-----| |------------------------|
; | ESI | <== | Process* next | +20
; |-----| |------------------------|
; Set [EXTERN Process* current] to the value in ESI
; Process* current <== ESI (Process* next)
mov [current], esi
mov esp, [esi + PCB.STACK_POINTER]
; |-----| |-----|
; | ESP | <== | ESI |
; |-----| |-----|
; Restore non-volatile registers (per the 32-bit System V ABI)
pop ebp
pop edi
pop esi
pop ebx
; The stack is now restored to its original state.
; __________Stack___________
; |------------------------|
; | Return Address (EIP) | +0
; |------------------------|
; | Process* next | +4
; |------------------------|
ret
+101
View File
@@ -0,0 +1,101 @@
#include "../include/task.h"
#include "../include/stdio.h"
#include "../include/paging.h"
Process* current = 0;
Process* queue = 0;
uint32_t irq_disable_counter = 0;
uint32_t pid_counter;
uint32_t task_count;
#define STACK_SIZE 4096
extern void switchProcess(Process* next);
static void processStartup()
{
printf("startup\n");
scheduler_unlock();
}
Process* task_create(EntryPoint func)
{
Process* p = heap_alloc(sizeof(Process));
p->pid = ++pid_counter;
p->state = Ready;
p->programCounter = 0;
p->stackBase = heap_alloc(STACK_SIZE);
p->stackPointer = (uintptr_t*)((uint32_t)p->stackBase + STACK_SIZE);
*(--p->stackPointer) = (uintptr_t)func;//TODO: check this shit
*(--p->stackPointer) = (uintptr_t)processStartup;
*(--p->stackPointer) = 0;
*(--p->stackPointer) = 0;
*(--p->stackPointer) = 0;
*(--p->stackPointer) = 0;
p->next = 0;
if(!queue)
{
queue = p;
current = queue;
}
else
{
Process* curr = queue;
while(curr->next)
curr = curr->next;
curr->next = p;
}
task_count++;
return p;
}
void scheduler_lock()
{
asm volatile("cli");
irq_disable_counter++;
}
void scheduler_unlock()
{
irq_disable_counter--;
if(irq_disable_counter == 0)
asm volatile("sti");
}
void schedule()
{
if(!current)
return;
Process* next = current->next;
if(!next)
next = queue;
switchProcess(next);
}
void idle()
{
while(1){}
}
void task1()
{
while(1){printf("task1\n");}
}
void task2()
{
while(1){printf("task2\n");}
}
void scheduler_init()
{
task_create(&idle);
task_create(&task1);
task_create(&task2);
}