diff options
Diffstat (limited to 'src/stem/task')
-rw-r--r-- | src/stem/task/idt.c | 178 | ||||
-rw-r--r-- | src/stem/task/idt.h | 33 | ||||
-rw-r--r-- | src/stem/task/idt_.asm | 143 | ||||
-rw-r--r-- | src/stem/task/task.c | 123 | ||||
-rw-r--r-- | src/stem/task/task.h | 41 | ||||
-rw-r--r-- | src/stem/task/task_.asm | 10 | ||||
-rw-r--r-- | src/stem/task/timer.c | 36 | ||||
-rw-r--r-- | src/stem/task/timer.h | 10 |
8 files changed, 574 insertions, 0 deletions
diff --git a/src/stem/task/idt.c b/src/stem/task/idt.c new file mode 100644 index 0000000..b9bd1ef --- /dev/null +++ b/src/stem/task/idt.c @@ -0,0 +1,178 @@ +#include "idt.h" +#include <core/monitor.h> +#include <core/sys.h> +#include <mem/paging.h> +#include "task.h" + +#include <stdlib.h> + +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +extern void idt_flush(int32_t ptr); + +struct idt_entry idt_entries[256]; +struct idt_ptr idt_ptr; + +static int_callback irq_handlers[16] = {0}; + +void idt_isrHandler(struct registers regs) { + if ((regs.int_no == 14 && paging_fault(®s) == 0) || regs.int_no != 14) { + if (tasking_handleException(®s) == 0) { + monitor_write(" >> >> SOMETHING BAD HAPPENNED << <<\n"); + monitor_write("Unhandled exception "); + monitor_writeHex(regs.int_no); + monitor_write(" @"); monitor_writeHex(regs.eip); + monitor_put('\n'); + PANIC("unhandled exception"); + } + } +} + +void idt_irqHandler(struct registers regs) { + uint32_t doSwitch = 0; + doSwitch |= (regs.int_no == 32); //IRQ0 = timer + if (regs.err_code > 7) { + outb(0xA0, 0x20); + } + outb(0x20, 0x20); + if (irq_handlers[regs.err_code] != 0) { + irq_handlers[regs.err_code](®s); + } else { + monitor_write("Unhandled IRQ "); monitor_writeHex(regs.int_no - 32); monitor_write("\n"); + } + if (doSwitch) tasking_switch(); +} + +static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { + idt_entries[num].base_lo = base & 0xFFFF; + idt_entries[num].base_hi = (base >> 16) & 0xFFFF; + + idt_entries[num].sel = sel; + idt_entries[num].always0 = 0; + idt_entries[num].flags = flags; +} + +void idt_init() { + idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1; + idt_ptr.base = (uint32_t)&idt_entries; + + memset((uint8_t*)&idt_entries, 0, sizeof(struct idt_entry) * 256); + + //Remap the IRQ table + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, 0x20); + outb(0xA1, 0x28); + outb(0x21, 0x04); + outb(0xA1, 0x02); + outb(0x21, 0x01); + outb(0xA1, 0x01); + outb(0x21, 0x0); + outb(0xA1, 0x0); + + idt_setGate(0, (int32_t)isr0, 0x08, 0x8E); + idt_setGate(1, (int32_t)isr1, 0x08, 0x8E); + idt_setGate(2, (int32_t)isr2, 0x08, 0x8E); + idt_setGate(3, (int32_t)isr3, 0x08, 0x8E); + idt_setGate(4, (int32_t)isr4, 0x08, 0x8E); + idt_setGate(5, (int32_t)isr5, 0x08, 0x8E); + idt_setGate(6, (int32_t)isr6, 0x08, 0x8E); + idt_setGate(7, (int32_t)isr7, 0x08, 0x8E); + idt_setGate(8, (int32_t)isr8, 0x08, 0x8E); + idt_setGate(9, (int32_t)isr9, 0x08, 0x8E); + idt_setGate(10, (int32_t)isr10, 0x08, 0x8E); + idt_setGate(11, (int32_t)isr11, 0x08, 0x8E); + idt_setGate(12, (int32_t)isr12, 0x08, 0x8E); + idt_setGate(13, (int32_t)isr13, 0x08, 0x8E); + idt_setGate(14, (int32_t)isr14, 0x08, 0x8E); + idt_setGate(15, (int32_t)isr15, 0x08, 0x8E); + idt_setGate(16, (int32_t)isr16, 0x08, 0x8E); + idt_setGate(17, (int32_t)isr17, 0x08, 0x8E); + idt_setGate(18, (int32_t)isr18, 0x08, 0x8E); + idt_setGate(19, (int32_t)isr19, 0x08, 0x8E); + idt_setGate(20, (int32_t)isr20, 0x08, 0x8E); + idt_setGate(21, (int32_t)isr21, 0x08, 0x8E); + idt_setGate(22, (int32_t)isr22, 0x08, 0x8E); + idt_setGate(23, (int32_t)isr23, 0x08, 0x8E); + idt_setGate(24, (int32_t)isr24, 0x08, 0x8E); + idt_setGate(25, (int32_t)isr25, 0x08, 0x8E); + idt_setGate(26, (int32_t)isr26, 0x08, 0x8E); + idt_setGate(27, (int32_t)isr27, 0x08, 0x8E); + idt_setGate(28, (int32_t)isr28, 0x08, 0x8E); + idt_setGate(29, (int32_t)isr29, 0x08, 0x8E); + idt_setGate(30, (int32_t)isr30, 0x08, 0x8E); + idt_setGate(31, (int32_t)isr31, 0x08, 0x8E); + + idt_setGate(32, (int32_t)irq0, 0x08, 0x8E); + idt_setGate(33, (int32_t)irq1, 0x08, 0x8E); + idt_setGate(34, (int32_t)irq2, 0x08, 0x8E); + idt_setGate(35, (int32_t)irq3, 0x08, 0x8E); + idt_setGate(36, (int32_t)irq4, 0x08, 0x8E); + idt_setGate(37, (int32_t)irq5, 0x08, 0x8E); + idt_setGate(38, (int32_t)irq6, 0x08, 0x8E); + idt_setGate(39, (int32_t)irq7, 0x08, 0x8E); + idt_setGate(40, (int32_t)irq8, 0x08, 0x8E); + idt_setGate(41, (int32_t)irq9, 0x08, 0x8E); + idt_setGate(42, (int32_t)irq10, 0x08, 0x8E); + idt_setGate(43, (int32_t)irq11, 0x08, 0x8E); + idt_setGate(44, (int32_t)irq12, 0x08, 0x8E); + idt_setGate(45, (int32_t)irq13, 0x08, 0x8E); + idt_setGate(46, (int32_t)irq14, 0x08, 0x8E); + idt_setGate(47, (int32_t)irq15, 0x08, 0x8E); + + idt_flush((int32_t)&idt_ptr); + + monitor_write("IDT ok\n"); +} + +void idt_handleIrq(int number, int_callback func) { + irq_handlers[number] = func; +} diff --git a/src/stem/task/idt.h b/src/stem/task/idt.h new file mode 100644 index 0000000..bb89013 --- /dev/null +++ b/src/stem/task/idt.h @@ -0,0 +1,33 @@ +#ifndef DEF_IDT_H +#define DEF_IDT_H + +#include <types.h> + +struct idt_entry { + uint16_t base_lo; //Low part of address to jump to + uint16_t sel; //Kernel segment selector + uint8_t always0; + uint8_t flags; //Flags + uint16_t base_hi; //High part of address to jump to +} __attribute__((packed)); + +struct idt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +struct registers { + uint32_t cr3; //page directory physical address + uint32_t ds; // Data segment selector + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha. + uint32_t int_no, err_code; // Interrupt number and error code (if applicable) + uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically. +}; + +typedef void (*int_callback)(struct registers*); + +void idt_init(); +void idt_handleIrq(int number, int_callback func); + +#endif + diff --git a/src/stem/task/idt_.asm b/src/stem/task/idt_.asm new file mode 100644 index 0000000..b73f7a5 --- /dev/null +++ b/src/stem/task/idt_.asm @@ -0,0 +1,143 @@ +; UNRELATED + +[GLOBAL gdt_flush] + +gdt_flush: + mov eax, [esp+4] + lgdt [eax] + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + jmp 0x08:.flush + +.flush: + ret + +; RELATED + +[GLOBAL idt_flush] +idt_flush: + mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter. + lidt [eax] ; Load the IDT pointer. + ret + +;************************************************************************************ + +%macro COMMONSTUB 1 +[EXTERN idt_%1Handler] +%1_common_stub: + pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax + + mov ax, ds ; Lower 16-bits of eax = ds. + push eax ; save the data segment descriptor + + mov ax, 0x10 ; load the kernel data segment descriptor + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + mov eax, cr3 + push eax + + call idt_%1Handler + + pop eax + mov cr3, eax + + pop eax ; reload the original data segment descriptor + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; Pops edi,esi,ebp... + add esp, 8 ; Cleans up the pushed error code and pushed ISR number + sti + iret +%endmacro + +COMMONSTUB isr +COMMONSTUB irq + +;************************************************************************************ + +%macro ISR_NOERRCODE 1 ; define a macro, taking one parameter + [GLOBAL isr%1] ; %1 accesses the first parameter. + isr%1: + cli + push byte 0 + push byte %1 + jmp isr_common_stub +%endmacro + +%macro ISR_ERRCODE 1 + [GLOBAL isr%1] + isr%1: + cli + push byte %1 + jmp isr_common_stub +%endmacro + +%macro IRQ 2 + [GLOBAL irq%1] + irq%1: + cli + push byte %1 ;push irq number + push byte %2 ;push int number + jmp irq_common_stub +%endmacro + +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_NOERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_NOERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 diff --git a/src/stem/task/task.c b/src/stem/task/task.c new file mode 100644 index 0000000..39c2482 --- /dev/null +++ b/src/stem/task/task.c @@ -0,0 +1,123 @@ +#include "task.h" +#include <core/sys.h> +#include <core/monitor.h> +#include <mem/mem.h> +#include "timer.h" + +#define KSTACKSIZE 0x8000 + +//From task_.asm +extern uint32_t read_eip(); +extern void task_idle(void*); + +static uint32_t thread_runnable(struct thread *th); + +uint32_t nextpid = 1; + +struct process *processes = 0; +struct thread *threads = 0, *current_thread = 0; + +void tasking_init(thread_entry whereToGo, void *data) { + cli(); + struct process *pr = kmalloc(sizeof(struct process)); //This process must be hidden to users + pr->pid = pr->uid = 0; + pr->parent = pr; + pr->pagedir = kernel_pagedir; + pr->next = 0; + current_thread = 0; + thread_new(pr, task_idle, 0); + thread_new(pr, whereToGo, data); + sti(); + monitor_write("Tasking starting\n"); + tasking_switch(); +} + +static struct thread *thread_next() { //NOT OPTIMAL : will allocate time slices to idle thread even if busy + if (current_thread == 0) current_thread = threads; + struct thread *ret = current_thread; + while (1) { + ret = ret->next; + if (ret == 0) ret = threads; + if (thread_runnable(ret)) { + return ret; + } + } +} + +void tasking_switch() { + if (threads == 0) return; //no tasking yet + cli(); + + uint32_t esp, ebp, eip; + + asm volatile("mov %%esp, %0" : "=r"(esp)); + asm volatile("mov %%ebp, %0" : "=r"(ebp)); + eip = read_eip(); + + if (eip == 0x12345) { + return; + } + + if (current_thread != 0) { + current_thread->esp = esp; + current_thread->ebp = ebp; + current_thread->eip = eip; + } + + current_thread = thread_next(); + + asm volatile(" \ + mov %0, %%ebp; \ + mov %1, %%esp; \ + mov %2, %%ecx; \ + mov $0x12345, %%eax; \ + jmp *%%ecx;" + : : "r"(current_thread->ebp), "r"(current_thread->esp), "r"(current_thread->eip)); +} + +uint32_t tasking_handleException(struct registers *regs) { + if (threads == 0) return 0; //No tasking yet + return 0; +} + +static uint32_t thread_runnable(struct thread *t) { + if (t->state == TS_RUNNING) return 1; + if (t->state == TS_SLEEPING && timer_time() >= t->timeWait) return 1; + return 0; +} + +static void thread_run(struct thread *thread, thread_entry entry_point, void *data) { + pagedir_switch(thread->process->pagedir); + asm volatile("sti"); + entry_point(data); + asm volatile("int $64"); +} + +void thread_new(struct process *proc, thread_entry entry_point, void *data) { + struct thread *t = kmalloc(sizeof(struct thread)); + t->process = proc; + t->kernelStack_addr = kmalloc(KSTACKSIZE); + t->kernelStack_size = KSTACKSIZE; + + uint32_t *stack = (uint32_t*)((size_t)t->kernelStack_addr + t->kernelStack_size); + + //Pass parameters + stack--; *stack = (uint32_t)data; + stack--; *stack = (uint32_t)entry_point; + stack--; *stack = (uint32_t)t; + stack--; *stack = 0; + t->esp = (uint32_t)stack; + t->ebp = t->esp + 8; + t->eip = (uint32_t)thread_run; + + t->state = TS_RUNNING; + + if (threads == 0) { + threads = t; + } else { + struct thread *i = threads; + while (i->next != 0) i = i->next; + i->next = t; + } +} + diff --git a/src/stem/task/task.h b/src/stem/task/task.h new file mode 100644 index 0000000..e91aa8b --- /dev/null +++ b/src/stem/task/task.h @@ -0,0 +1,41 @@ +#ifndef DEF_TASK_H +#define DEF_TASK_H + +#include <types.h> +#include <mem/paging.h> +#include "idt.h" + +struct process { + uint32_t pid, uid; + struct process *parent; + struct page_directory *pagedir; + + struct process *next; //Forms a linked list +}; + +#define TS_RUNNING 0 +#define TS_SLEEPING 1 //Sleeping for a defined amount of time +#define TS_WAIKWAIT 2 //Waiting to be waked up by something precise (thread currently blocked) + +typedef void (*thread_entry)(void*); + +struct thread { + struct process *process; + uint32_t esp, ebp, eip; + uint8_t state; + uint32_t timeWait; + void* kernelStack_addr; + uint32_t kernelStack_size; + + struct thread *next; //Forms a linked list +}; + +extern struct thread *current_thread; + +void tasking_init(thread_entry whereToGo, void *data); +void tasking_switch(); +uint32_t tasking_handleException(struct registers *regs); + +void thread_new(struct process *proc, thread_entry entry_point, void *data); + +#endif diff --git a/src/stem/task/task_.asm b/src/stem/task/task_.asm new file mode 100644 index 0000000..ae45c68 --- /dev/null +++ b/src/stem/task/task_.asm @@ -0,0 +1,10 @@ +[GLOBAL read_eip] +read_eip: + pop eax + jmp eax + +[GLOBAL task_idle] +task_idle: + sti + hlt + jmp task_idle diff --git a/src/stem/task/timer.c b/src/stem/task/timer.c new file mode 100644 index 0000000..8c1a2b8 --- /dev/null +++ b/src/stem/task/timer.c @@ -0,0 +1,36 @@ +#include "timer.h" +#include "idt.h" +#include <core/sys.h> +#include <core/monitor.h> + +static uint32_t tick = 0, frequency = 0, uptime = 0; + +void timer_callback(struct registers *regs) { + tick++; + if (tick == frequency) { + uptime++; + tick = 0; + } +} + +uint32_t timer_uptime() { return uptime; } + +uint32_t timer_time() { + return (uptime * 1000) + (tick * 1000 / frequency); +} + +void timer_init(uint32_t freq) { + frequency = freq; + + idt_handleIrq(0, timer_callback); + + uint32_t divisor = 1193180 / freq; + + outb(0x43, 0x36); //Command byte + + uint8_t l = (divisor & 0xFF), h = (divisor >> 8); + outb(0x40, l); + outb(0x40, h); + + monitor_write("Timer started\n"); +} diff --git a/src/stem/task/timer.h b/src/stem/task/timer.h new file mode 100644 index 0000000..4909245 --- /dev/null +++ b/src/stem/task/timer.h @@ -0,0 +1,10 @@ +#ifndef DEF_TIMER_H +#define DEF_TIMER_H + +#include <types.h> + +void timer_init(uint32_t frequency); +uint32_t timer_time(); //Returns miliseconds (approximate) since computer started +uint32_t timer_uptime(); //Same thing in seconds + +#endif |