diff --git a/Makefile b/Makefile index 86e4b68..34f836a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # 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 CC = gcc -D__is_katauos @@ -96,6 +96,12 @@ bin/paging.o: src/paging.c bin/fat.o: src/fat.c $(CC) $(CFLAGS) -c $< -o $@ +bin/switch.o: src/switch.asm + $(AS) $(ASFLAGS) $< -o $@ + +bin/task.o: src/task.c + $(CC) $(CFLAGS) -c $< -o $@ + clean: rm -rf bin/ rm -f $(OUTPUT) diff --git a/include/task.h b/include/task.h new file mode 100644 index 0000000..e450c9e --- /dev/null +++ b/include/task.h @@ -0,0 +1,32 @@ +#ifndef TASK_H +#define TASK_H + +#include + +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 diff --git a/src/isr.c b/src/isr.c index b7335b2..68a6814 100644 --- a/src/isr.c +++ b/src/isr.c @@ -4,6 +4,7 @@ #include "../include/pic.h" #include "../include/pit.h" #include "../include/keyboard.h" +#include "../include/task.h" #include @@ -75,6 +76,10 @@ __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame) { pit_init(100); pic_end_int(0x0); + + scheduler_lock(); + schedule(); + scheduler_unlock(); } __attribute__((interrupt)) void isr_custom(struct interrupt_frame *frame) diff --git a/src/kernel.c b/src/kernel.c index dbe8272..e4d1569 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -8,6 +8,7 @@ #include "../include/pit.h" #include "../include/paging.h" #include "../include/fat.h" +#include "../include/task.h" #include @@ -151,6 +152,7 @@ void kmain() heap_init(); printf("after heap_init\n"); __asm__ __volatile__ ("sti"); + scheduler_init(); printf("Kernel init sequence completed\n"); char yooo[256] = "heheh"; diff --git a/src/switch.asm b/src/switch.asm new file mode 100644 index 0000000..277e7ca --- /dev/null +++ b/src/switch.asm @@ -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 diff --git a/src/task.c b/src/task.c new file mode 100644 index 0000000..994455d --- /dev/null +++ b/src/task.c @@ -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); +}