implement basic multitasking
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user