diff --git a/headers/assert.h b/headers/assert.h new file mode 100644 index 0000000..fb1a667 --- /dev/null +++ b/headers/assert.h @@ -0,0 +1,11 @@ +#pragma once + +#include "kpanic.h" + +#define assert(X) \ + do { \ + if (!(X)) { \ + kpanic("ASSERT_FAIL %s:%u %s\n", __FILE__, __LINE__, \ + #X); \ + } \ + } while (0) diff --git a/headers/debug.h b/headers/debug.h index 71cf026..4da0834 100644 --- a/headers/debug.h +++ b/headers/debug.h @@ -9,13 +9,6 @@ #define PRINT_STR(X) kprintf("%s:%u %s: %s\n", __FILE__, __LINE__, #X, X) #define PRINT_UINT(X) kprintf("%s:%u %s: %u\n", __FILE__, __LINE__, #X, X) #define PRINT_INT(X) kprintf("%s:%u %s: %d\n", __FILE__, __LINE__, #X, X) -#define assert(X) \ - do { \ - if (!(X)) { \ - kpanic("ASSERT_FAIL %s:%u %s\n", __FILE__, __LINE__, \ - #X); \ - } \ - } while (0) struct function_entry { uint32_t addr; diff --git a/headers/process.h b/headers/process.h new file mode 100644 index 0000000..7b14a41 --- /dev/null +++ b/headers/process.h @@ -0,0 +1,25 @@ +#pragma once + +#include "signal.h" + +#include + +extern struct pcb *current_pcb; + +enum owner { OWNER_KERNEL, OWNER_USER }; + +struct pcb { + void *cr3; + uint32_t *heap; + uint16_t pid; + uint8_t uid; + struct signal_data signals; + struct pcb *next; + struct pcb *prev; + struct tcb *thread_list; +}; + +void switch_process(struct pcb *next_pcb); +struct pcb *create_process(uint8_t uid); +int8_t create_kernel_process(void); +void remove_process(struct pcb *pcb); diff --git a/headers/scheduler.h b/headers/scheduler.h new file mode 100644 index 0000000..b345f02 --- /dev/null +++ b/headers/scheduler.h @@ -0,0 +1,3 @@ +#pragma once + +void scheduler(void); diff --git a/headers/task.h b/headers/task.h deleted file mode 100644 index 4fd9835..0000000 --- a/headers/task.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "list.h" -#include "memory.h" -#include "signal.h" - -#include - -extern struct task *current_task; - -enum status { ZOMBIE, THREAD, RUN, WAIT, SLEEP, STOPPED, FORKED }; -enum owner { OWNER_KERNEL, OWNER_USER }; - -#define STACK_SIZE PAGE_SIZE * 4 - -struct task { - uint8_t *esp; - uint8_t *esp0; - uint32_t *cr3; // physical - uint32_t *heap; // virtual - uint32_t *eip; - uint16_t pid; - uint8_t status; - uint8_t uid; - struct task *daddy; - struct task *child; - struct signal_data signals; - struct task *next; - struct task *prev; -}; - -void scheduler(void); -void switch_to_task(struct task *next_task); -struct task *create_task(uint8_t uid); -int8_t create_kernel_task(void); -void remove_task(struct task *task); -struct task *copy_task(const struct task *task); -void kfork(struct task *daddy); -void zombify_task(struct task *task); - -// utils -void exec_fn(void (*fn)(void)); -uint16_t fork(void); -uint16_t wait(void); diff --git a/headers/thread.h b/headers/thread.h new file mode 100644 index 0000000..7fbf4de --- /dev/null +++ b/headers/thread.h @@ -0,0 +1,27 @@ +#pragma once + +#include "process.h" + +#include + +#define STACK_SIZE PAGE_SIZE * 4 + +typedef enum { + NEW, + RUNNING, + WAITING, + STOPPED, +} state_t; + +struct tcb { + uint8_t *esp; + uint8_t *esp0; + uint16_t tid; + state_t state; + struct pcb *process; + struct tcb *next; +}; + +struct tcb *create_thread(struct pcb *process, void (*routine)(void)); +void delete_thread(struct tcb *thread); +void switch_thread(struct tcb *thread_to_switch); diff --git a/src/drivers/clock.c b/src/drivers/clock.c index 4ef66a9..86591ec 100644 --- a/src/drivers/clock.c +++ b/src/drivers/clock.c @@ -5,8 +5,9 @@ #include "interrupts.h" #include "kprintf.h" #include "memory.h" +#include "process.h" +#include "scheduler.h" #include "sys/io.h" -#include "task.h" #define PIT_CHANNEL0 0x40 #define PIT_FREQUENCY 1193182 diff --git a/src/interrupt/irq.s b/src/interrupt/irq.s index b57e922..538ef2f 100644 --- a/src/interrupt/irq.s +++ b/src/interrupt/irq.s @@ -38,7 +38,6 @@ irq_common_stub: iret irq0: - mov [esp_backup], esp push 0 push 32 jmp irq_common_stub diff --git a/src/kernel.c b/src/kernel.c index 811d9b4..500b4be 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -8,9 +8,9 @@ #include "memory.h" #include "multiboot.h" #include "power.h" +#include "process.h" #include "shell.h" #include "string.h" -#include "task.h" #include "terminal.h" #include "time.h" #include "vbe.h" @@ -43,9 +43,9 @@ void kernel_main(multiboot_info_t *mbd, uint32_t magic) init_memory(mbd, magic); load_drivers(); terminal_initialize(); - create_kernel_task(); + create_kernel_process(); signal(4, bozo); kill(0, 4); - create_task(42); + // create_process(42); shell_init(); } diff --git a/src/memory/frame.c b/src/memory/frame.c index dd7ade7..fdec770 100644 --- a/src/memory/frame.c +++ b/src/memory/frame.c @@ -2,7 +2,7 @@ #include #include -#include "debug.h" +#include "assert.h" #include "kprintf.h" #include "memory.h" #include "string.h" diff --git a/src/memory/page.c b/src/memory/page.c index f7462da..cceedd0 100644 --- a/src/memory/page.c +++ b/src/memory/page.c @@ -2,11 +2,11 @@ #include #include -#include "debug.h" +#include "assert.h" #include "kprintf.h" #include "memory.h" #include "string.h" -#include "task.h" +#include "process.h" #include "utils.h" static int16_t find_next_block(size_t nb_pages, uint16_t *pd_index_ptr, diff --git a/src/memory/page_table.c b/src/memory/page_table.c index bf3fc33..9085ca3 100644 --- a/src/memory/page_table.c +++ b/src/memory/page_table.c @@ -1,4 +1,4 @@ -#include "debug.h" +#include "assert.h" #include "kprintf.h" #include "memory.h" void init_page_table(uint32_t page_table[1024], uint16_t start) diff --git a/src/memory/phys/allocator.c b/src/memory/phys/allocator.c index ec04044..560ff75 100644 --- a/src/memory/phys/allocator.c +++ b/src/memory/phys/allocator.c @@ -1,9 +1,9 @@ #include "alloc.h" -#include "debug.h" +#include "assert.h" #include "kpanic.h" #include "kprintf.h" #include "memory.h" -#include "task.h" +#include "process.h" Zone *kzones[3]; diff --git a/src/memory/phys/kmalloc.c b/src/memory/phys/kmalloc.c index 60328c5..34f41da 100644 --- a/src/memory/phys/kmalloc.c +++ b/src/memory/phys/kmalloc.c @@ -1,5 +1,5 @@ #include "alloc.h" -#include "debug.h" +#include "assert.h" #include "kprintf.h" #include "terminal.h" #include diff --git a/src/memory/virt/allocator.c b/src/memory/virt/allocator.c index ec465e3..853cce0 100644 --- a/src/memory/virt/allocator.c +++ b/src/memory/virt/allocator.c @@ -1,9 +1,9 @@ #include "alloc.h" -#include "debug.h" +#include "assert.h" #include "kpanic.h" #include "kprintf.h" #include "memory.h" -#include "task.h" +#include "process.h" Zone *vzones[3]; diff --git a/src/memory/virt/vmalloc.c b/src/memory/virt/vmalloc.c index 31a23b8..0cc2661 100644 --- a/src/memory/virt/vmalloc.c +++ b/src/memory/virt/vmalloc.c @@ -1,5 +1,5 @@ #include "alloc.h" -#include "debug.h" +#include "assert.h" #include "kprintf.h" #include "terminal.h" #include diff --git a/src/multitasking/fork.c b/src/multitasking/fork.c deleted file mode 100644 index b893152..0000000 --- a/src/multitasking/fork.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "interrupts.h" -#include "kprintf.h" -#include "task.h" - -uint16_t fork(void) -{ - current_task->status = FORKED; - scheduler(); - return current_task->child ? current_task->child->pid : 0; -} - -void kfork(struct task *daddy) -{ - cli(); - struct task *child = copy_task(daddy); - if (!child) { - kprintf(KERN_ALERT "Fork failed ! retry at the next loop"); - toris(); - return; - } - child->daddy = daddy; - daddy->child = child; - daddy->status = RUN; - child->status = RUN; - toris(); -} diff --git a/src/multitasking/process.c b/src/multitasking/process.c new file mode 100644 index 0000000..cc759ee --- /dev/null +++ b/src/multitasking/process.c @@ -0,0 +1,57 @@ +#include "process.h" +#include "alloc.h" +#include "interrupts.h" +#include "memory.h" + +#include "string.h" + +int8_t create_kernel_process(void) +{ + struct pcb *new_pcb = vmalloc(sizeof(struct pcb)); + if (!new_pcb) + return -1; + new_pcb->pid = 0; + new_pcb->uid = 0; + new_pcb->heap = kernel_pd; + new_pcb->cr3 = (uint32_t *)((uint32_t)kernel_pd - HEAP_END); + new_pcb->next = new_pcb; + new_pcb->prev = new_pcb; + return 0; +} + +struct pcb *create_process(uint8_t uid) +{ + static uint32_t pid = 1; + struct pcb *new_pcb = vmalloc(sizeof(struct pcb)); + if (!new_pcb) + return NULL; + new_pcb->uid = uid; + new_pcb->pid = pid++; + + new_pcb->heap = alloc_pages(4096, &new_pcb->cr3); + if (!new_pcb->heap) { + vfree(new_pcb); + return NULL; + } + memcpy(new_pcb->heap, current_pcb->heap, 4096); + new_pcb->next = current_pcb->next; + new_pcb->prev = current_pcb; + current_pcb->next = new_pcb; + if (current_pcb->prev == current_pcb) + current_pcb->prev = new_pcb; + + new_pcb->signals.pending = SIG_IGN; + + return new_pcb; +} + +void remove_pcb(struct pcb *pcb) +{ + struct pcb *left = pcb->prev; + struct pcb *right = pcb->next; + if (pcb->heap) + free_pages(pcb->heap, 4096); + left->next = right; + right->prev = left; + vfree(pcb); +} diff --git a/src/multitasking/scheduler.c b/src/multitasking/scheduler.c index f3bded5..ecd7d4c 100644 --- a/src/multitasking/scheduler.c +++ b/src/multitasking/scheduler.c @@ -2,34 +2,28 @@ #include "debug.h" #include "interrupts.h" #include "kprintf.h" -#include "task.h" +#include "process.h" +#include "thread.h" #include "time.h" #include -struct task *current_task; +struct pcb *current_pcb; +struct tcb *current_tcb; void scheduler(void) { - // ZOMBIE, THREAD, RUN, WAIT, SLEEP, STOPPED, FORKED - void (*func[])(struct task *) = { - zombify_task, NULL, NULL, NULL, NULL, remove_task, kfork, - }; - - if (!current_task) // || current_task->next == current_task) - return; - cli(); - switch_pd(kernel_pd, (uint32_t *)((uint32_t)kernel_pd - HEAP_END)); - struct task *it = current_task->next; - while (it && it->status != RUN) { - if (it != current_task && func[it->status]) { - struct task *new_it = it->prev; - func[it->status](it); - it = new_it; + struct tcb *thread_to_switch; + if (!current_tcb) { + thread_to_switch = current_pcb->thread_list; + } else { + if (!current_tcb->next) { + current_pcb = current_pcb->next; + // TODO switch context + thread_to_switch = current_pcb->thread_list; + } else { + thread_to_switch = current_tcb->next; } - it = it->next; } - switch_to_task(it); - exec_signal_pending(); - toris(); + switch_thread(thread_to_switch); } diff --git a/src/multitasking/switch_to_task.s b/src/multitasking/switch_to_task.s deleted file mode 100644 index d1ffa5c..0000000 --- a/src/multitasking/switch_to_task.s +++ /dev/null @@ -1,58 +0,0 @@ -.intel_syntax noprefix - -.section .text - .global switch_to_task - -switch_to_task: - push ebx - push ebp - push edi - push esi - - mov eax, [current_task] - - // save the current stack pointer to the old stack - mov [eax+0], 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 eax, [current_task] - - mov esp, [eax+0] // get esp - - mov ecx, [eax+12] // get task's pd - mov [current_pd], ecx - mov ecx, [eax+8] - mov cr3, ecx - - pop esi - pop edi - pop ebp - pop ebx - - - mov ecx, 0 - - cmp [eax+16], ecx - je .END - - sti - - push [eax+16] // store func_ptr - - mov [eax+16], ecx // clear eip in current_task - - push 0 - call pic_send_eoi - pop edx // remove pic_send_eoi argument - - pop edx // get func_ptr - call edx - - call exit_task - -.END: - ret diff --git a/src/multitasking/switch_to_thread.s b/src/multitasking/switch_to_thread.s new file mode 100644 index 0000000..90a8d4a --- /dev/null +++ b/src/multitasking/switch_to_thread.s @@ -0,0 +1,31 @@ +.intel_syntax noprefix + +.section .text + .global switch_thread + +switch_thread: + push ebx + push ebp + push edi + push esi + + mov eax, [current_tcb] + + // save the current stack pointer to the old stack + mov [eax+0], esp + + // stack pointer + the 4 regs pushed + // and + 1 to get the argument (next thread) + mov esi, [esp+(4+1)*4] + mov [current_tcb], esi + + mov eax, [current_tcb] + + mov esp, [eax+0] // get esp + + pop esi + pop edi + pop ebp + pop ebx + + iret diff --git a/src/multitasking/task.c b/src/multitasking/task.c deleted file mode 100644 index a295df4..0000000 --- a/src/multitasking/task.c +++ /dev/null @@ -1,140 +0,0 @@ -#include "task.h" -#include "alloc.h" -#include "debug.h" -#include "interrupts.h" -#include "kpanic.h" -#include "kprintf.h" -#include "memory.h" -#include "string.h" - -#include -#include - -uint32_t esp_backup; - -struct task *create_task(uint8_t uid) -{ - static uint32_t pid = 1; - switch_pd(kernel_pd, (uint32_t *)((uint32_t)kernel_pd - HEAP_END)); - struct task *new_task = vmalloc(sizeof(struct task)); - if (!new_task) { - switch_pd(current_task->heap, current_task->cr3); - return NULL; - } - switch_pd(current_task->heap, current_task->cr3); - new_task->status = RUN; - new_task->uid = uid; - new_task->esp = new_task->esp0 + STACK_SIZE; - new_task->pid = pid++; - - // Allocate new pd - new_task->heap = alloc_pages(4096, (void **)&new_task->cr3); - if (!new_task->heap) { - vfree(new_task); - return NULL; - } - new_task->heap[768] = ((uint32_t)boot_page_table1 - HEAP_END) | 0x03; - // memcpy(new_task->heap, current_task->heap, 4096); - current_pd = new_task->heap; - // switch_pd(new_task->heap, new_task->cr3); - - // Allocate new stack on the newly allocated pd - new_task->esp0 = alloc_pages(STACK_SIZE, NULL); - current_pd = kernel_pd; - // switch_pd(current_task->heap, current_task->cr3); - if (!new_task->esp0) { - vfree(new_task); - free_pages(new_task->heap, 4096); - return NULL; - } - - new_task->next = current_task->next; - new_task->prev = current_task; - current_task->next = new_task; - if (current_task->prev == current_task) - current_task->prev = new_task; - - new_task->signals.pending = SIG_IGN; - - return new_task; -} - -int8_t create_kernel_task(void) -{ - struct task *new_task = vmalloc(sizeof(struct task)); - if (!new_task) - return -1; - new_task->status = RUN; - new_task->uid = 0; - new_task->pid = 0; - new_task->heap = kernel_pd; - new_task->cr3 = (uint32_t *)((uint32_t)kernel_pd - HEAP_END); - new_task->prev = new_task; - new_task->next = new_task; - new_task->signals.pending = SIG_IGN; - current_task = new_task; - return 0; -} - -void exec_fn(void (*fn)(void)) -{ - struct task *new_task = create_task(OWNER_KERNEL); - if (!new_task) - kpanic("failed to create new task"); - new_task->eip = (uint32_t *)fn; -} - -void zombify_task(struct task *task) -{ - cli(); // Technically useless - free_pages(task->heap, 4096); - free_pages(task->esp0, STACK_SIZE); - task->esp0 = NULL; - task->heap = NULL; - toris(); -} - -void remove_task(struct task *task) -{ - cli(); - struct task *left = task->prev; - struct task *right = task->next; - - if (task->child) { - remove_task(task->child); - task->child = NULL; - } - if (task->heap) - free_pages(task->heap, 4096); - if (task->esp0) - free_pages(task->esp0, STACK_SIZE); - left->next = right; - right->prev = left; - vfree(task); - toris(); -} - -struct task *copy_task(const struct task *task) -{ - struct task *new_task = create_task(task->uid); - if (!new_task) - return NULL; - memcpy(new_task->esp0, task->esp0, STACK_SIZE); - new_task->esp = new_task->esp0 + (task->esp - task->esp0); - new_task->status = task->status; - return new_task; -} - -void exit_task(void) -{ - cli(); - if (current_task->daddy && current_task->daddy->status != WAIT) - current_task->status = ZOMBIE; - else { - if (current_task->daddy->status == WAIT) - current_task->daddy->status = RUN; - current_task->status = STOPPED; - } - toris(); - scheduler(); -} diff --git a/src/multitasking/thread.c b/src/multitasking/thread.c new file mode 100644 index 0000000..48b7dc9 --- /dev/null +++ b/src/multitasking/thread.c @@ -0,0 +1,47 @@ +#include "thread.h" +#include "alloc.h" +#include "assert.h" +#include "interrupts.h" +#include "memory.h" +#include "string.h" +#include "thread.h" + +struct tcb *create_thread(struct pcb *process, void (*routine)(void)) +{ + static uint32_t tid = 1; + struct tcb *new_tcb = vmalloc(sizeof(struct tcb)); + if (!new_tcb) + return NULL; + new_tcb->tid = tid++; + + new_tcb->esp0 = alloc_pages(STACK_SIZE, NULL); + if (!new_tcb->esp0) { + vfree(new_tcb); + return NULL; + } + // set esp to "skip" the 4 GPRs and eip later to be used as the context + // of the thread + new_tcb->esp = new_tcb->esp0 + STACK_SIZE - 5 * 4; + memcpy(new_tcb->esp + 4, routine, 4); + new_tcb->process = process; + new_tcb->next = NULL; + new_tcb->state = NEW; + + struct tcb *it = process->thread_list; + while (it) + it = it->next; + it = new_tcb; + + return new_tcb; +} + +void delete_thread(struct tcb *thread) +{ + vfree(thread->esp0); + struct tcb *it = thread->process->thread_list; + assert(it); + while (it->next != thread) + it = it->next; + it->next = it->next->next; + vfree(thread); +} diff --git a/src/multitasking/wait.c b/src/multitasking/wait.c deleted file mode 100644 index 46f914a..0000000 --- a/src/multitasking/wait.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "interrupts.h" -#include "task.h" - -uint16_t wait(void) -{ - if (current_task->child == NULL) - return -1; - cli(); - if (current_task->child->status == ZOMBIE) - current_task->child->status = STOPPED; - else - current_task->status = WAIT; - uint16_t child_pid = current_task->child->pid; - toris(); - scheduler(); - return child_pid; -} diff --git a/src/signal/signal.c b/src/signal/signal.c index a94cd18..964230c 100644 --- a/src/signal/signal.c +++ b/src/signal/signal.c @@ -1,21 +1,21 @@ #include "signal.h" #include "kprintf.h" -#include "task.h" +#include "process.h" #include void signal(SIGNAL_CODE sig_num, void *handler) { - current_task->signals.handlers[sig_num] = handler; + current_pcb->signals.handlers[sig_num] = handler; } void kill(int pid, SIGNAL_CODE sig_num) { - struct task *task = current_task; + struct pcb *pcb = current_pcb; - while (task->pid != pid) - task = task->next; + while (pcb->pid != pid) + pcb = pcb->next; - task->signals.pending = sig_num; + pcb->signals.pending = sig_num; } static void display_signal(SIGNAL_CODE sig_num) @@ -25,12 +25,12 @@ static void display_signal(SIGNAL_CODE sig_num) static void exec_signal(SIGNAL_CODE sig_num) { - void *handler = current_task->signals.handlers[sig_num]; + void *handler = current_pcb->signals.handlers[sig_num]; - if (handler == SIG_IGN) + if ((int32_t)handler == SIG_IGN) return; - if (handler == SIG_DFL) { + if ((int32_t)handler == SIG_DFL) { display_signal(sig_num); return; } @@ -41,9 +41,9 @@ static void exec_signal(SIGNAL_CODE sig_num) void exec_signal_pending(void) { - uint32_t signal_code = current_task->signals.pending; + int32_t signal_code = current_pcb->signals.pending; if (signal_code != SIG_IGN) { exec_signal(signal_code); - current_task->signals.pending = SIG_IGN; + current_pcb->signals.pending = SIG_IGN; } -} \ No newline at end of file +}