diff --git a/headers/gdt.h b/headers/gdt.h index ac20269..42b85f7 100644 --- a/headers/gdt.h +++ b/headers/gdt.h @@ -1,9 +1,10 @@ #pragma once +#include "tss.h" #include #define GDT_ADDRESS 0xC0105040 -#define GDT_SIZE 7 +#define GDT_SIZE 8 // https://wiki.osdev.org/Global_Descriptor_Table#GDTR struct gdt_descriptor { @@ -11,6 +12,8 @@ struct gdt_descriptor { uint32_t base; } __attribute__((packed)); +extern struct tss TSS; + void init_gdt(); #define GDT_FLAG_64BIT_MODE 0b0010 @@ -39,3 +42,4 @@ extern uint8_t gdt_entries[GDT_SIZE * 8]; #define GDT_OFFSET_USER_CODE 0x20 #define GDT_OFFSET_USER_DATA 0x28 #define GDT_OFFSET_USER_STACK 0x30 +#define GDT_OFFSET_TSS 0x38 diff --git a/headers/task.h b/headers/task.h new file mode 100644 index 0000000..8a25ff7 --- /dev/null +++ b/headers/task.h @@ -0,0 +1,23 @@ +#pragma once + +#include "list.h" + +#include + +enum status { ZOMBIE, THREAD, RUN }; + +struct task { + uint32_t *esp; + uint32_t *esp0; + uint32_t *cr3; + uint16_t pid; + uint8_t status; + struct task *daddy; + struct task *child; + struct list **signals; + uint8_t owner_id; + struct task *next; +}; + +void scheduler(void); +void switch_to_task(struct task *next_task); diff --git a/headers/tss.h b/headers/tss.h new file mode 100644 index 0000000..9a5cfa3 --- /dev/null +++ b/headers/tss.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +// _h fields are for the offset +struct tss { + uint16_t link; + uint16_t link_h; + + uint32_t esp0; + uint16_t ss0; + uint16_t ss0_h; + + uint32_t esp1; + uint16_t ss1; + uint16_t ss1_h; + + uint32_t esp2; + uint16_t ss2; + uint16_t ss2_h; + + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + + uint32_t esp; + uint32_t ebp; + + uint32_t esi; + uint32_t edi; + + uint16_t es; + uint16_t es_h; + + uint16_t cs; + uint16_t cs_h; + + uint16_t ss; + uint16_t ss_h; + + uint16_t ds; + uint16_t ds_h; + + uint16_t fs; + uint16_t fs_h; + + uint16_t gs; + uint16_t gs_h; + + uint16_t ldt; + uint16_t ldt_h; + + uint16_t trap; + uint16_t iomap; +}; diff --git a/libbozo/headers/list.h b/libbozo/headers/list.h new file mode 100644 index 0000000..b69e9bc --- /dev/null +++ b/libbozo/headers/list.h @@ -0,0 +1,6 @@ +#pragma once + +struct list { + void *content; + struct list *next; +}; diff --git a/src/drivers/clock.c b/src/drivers/clock.c index 8f7bb0b..4d504e8 100644 --- a/src/drivers/clock.c +++ b/src/drivers/clock.c @@ -6,13 +6,15 @@ #include "kprintf.h" #include "memory.h" #include "sys/io.h" +#include "task.h" #define PIT_CHANNEL0 0x40 #define PIT_FREQUENCY 1193182 #define PIT_COUNT (65535 / 2) #define DELAY (1000 / (PIT_FREQUENCY / PIT_COUNT)) -uint32_t counter = 0; +uint32_t sleep_counter; +uint32_t scheduler_counter; static void clock_handler(struct registers *regs); @@ -36,12 +38,15 @@ void clock_init(struct registers *regs) static void clock_handler(struct registers *regs) { (void)regs; - counter--; + if (scheduler_counter % 10) + scheduler(); + scheduler_counter++; + sleep_counter--; } void sleep(uint64_t delay) { - counter = delay / DELAY; - while (counter) + sleep_counter = delay / DELAY; + while (sleep_counter) ; -} \ No newline at end of file +} diff --git a/src/gdt/gdt.c b/src/gdt/gdt.c index b571f60..2fdcc67 100644 --- a/src/gdt/gdt.c +++ b/src/gdt/gdt.c @@ -5,6 +5,7 @@ extern void set_gdt(uint32_t gdt_ptr); +struct tss TSS; uint8_t gdt_entries[GDT_SIZE * 8]; struct gdt_descriptor *gdtr = (struct gdt_descriptor *)GDT_ADDRESS; @@ -90,6 +91,9 @@ void init_gdt(void) GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User stack + // TSS + set_gdt_entry_value(gdt_entries + GDT_OFFSET_TSS, (uint32_t)&TSS, + sizeof(struct tss) - 1, 0x89, 0); set_gdt(((uint32_t)gdtr)); } diff --git a/src/kernel.c b/src/kernel.c index bc3b85f..2795f04 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -41,7 +41,5 @@ void kernel_main(multiboot_info_t *mbd, uint32_t magic) /* "complex 8*unknown quantity -byte descriptor table. -- Troy " */ /* "Martin 03:50, 22 March 2009 (UTC)\n"); */ - /* terminal_putchar('A'); */ - /* memset(display.buff, 255, 1024 * 1024); */ shell_init(); } diff --git a/src/multitasking/scheduler.c b/src/multitasking/scheduler.c new file mode 100644 index 0000000..815f6bb --- /dev/null +++ b/src/multitasking/scheduler.c @@ -0,0 +1,11 @@ +#include "task.h" + +struct task *current_task; + +void scheduler(void) +{ + struct task *it = current_task->next; + while (it->status != RUN) + it = it->next; + switch_to_task(it); +} diff --git a/src/multitasking/switch_to_task.s b/src/multitasking/switch_to_task.s new file mode 100644 index 0000000..6a426e2 --- /dev/null +++ b/src/multitasking/switch_to_task.s @@ -0,0 +1,37 @@ +.intel_syntax noprefix + +.section .text + .global switch_to_task + +switch_to_task: + push ebx + push ebp + push edi + push esi + + // save the current stack pointer to the old stack + mov [current_task], esp + + // stack pointer + the 4 regs pushed + // and + 1 to get the argument (next task) + mov esi, [esp+(4+1)*4] + mov [current_task], esi + + mov esp, [current_task] + mov eax, [current_task+4] + mov ebx, [current_task+8] + mov [TSS + 4], eax + mov ecx, cr3 + + // if cr3 hasn't change, do nothing + cmp ecx, ebx + je .END + mov cr3, ebx + +.END: + pop esi + pop edi + pop ebp + pop ebx + + ret