diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/Makefile | 3 | ||||
-rw-r--r-- | src/kernel/ipc/object.h | 26 | ||||
-rw-r--r-- | src/kernel/ipc/request.h | 29 | ||||
-rw-r--r-- | src/kernel/ipc/shm.c | 56 | ||||
-rw-r--r-- | src/kernel/ipc/shm.h | 24 | ||||
-rw-r--r-- | src/kernel/lib/mutex.c | 23 | ||||
-rw-r--r-- | src/kernel/lib/mutex.h | 15 | ||||
-rw-r--r-- | src/kernel/linker/elf.c | 2 | ||||
-rw-r--r-- | src/kernel/mem/seg.c | 6 | ||||
-rw-r--r-- | src/kernel/mem/seg.h | 7 | ||||
-rw-r--r-- | src/kernel/task/idt.c | 25 | ||||
-rw-r--r-- | src/kernel/task/idt.h | 3 | ||||
-rw-r--r-- | src/kernel/task/syscall.c | 2 | ||||
-rw-r--r-- | src/kernel/task/task.c | 18 | ||||
-rw-r--r-- | src/kernel/task/task.h | 5 |
15 files changed, 225 insertions, 19 deletions
diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 5af7f4b..3508bb9 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -12,8 +12,9 @@ AFLAGS = -f elf OBJECTS = core/loader_.o core/kmain.o core/sys.o \ core/monitor.o task/timer.o \ task/idt.o task/idt_.o task/task.o task/task_.o task/syscall.o \ - lib/stdlib.o lib/bitset.o \ + lib/stdlib.o lib/bitset.o lib/mutex.o \ mem/mem.o mem/paging.o mem/gdt.o mem/heap.o mem/seg.o \ + ipc/shm.o \ linker/elf.o OUT = kernel.elf diff --git a/src/kernel/ipc/object.h b/src/kernel/ipc/object.h new file mode 100644 index 0000000..ef90a66 --- /dev/null +++ b/src/kernel/ipc/object.h @@ -0,0 +1,26 @@ +#ifndef DEF_OBJECT_H +#define DEF_OBJECT_H + +#include <task/task.h> + +#define OS_INACTIVE 0 //No one doing anything on this +#define OS_LISTENING 1 //A thread is waiting for a request on this object +#define OS_REQUESTPENDING 2 //A request is waiting for a thread to handle it +#define OS_BUSY 3 //A thread is currently handling a request + +struct object { + struct process *owner; + int descriptors; + uint32_t busyMutex; + struct request *request; +}; + +struct obj_descriptor { + struct object *obj; + int id; + int owned; + struct obj_descriptor *next; +}; + +#endif + diff --git a/src/kernel/ipc/request.h b/src/kernel/ipc/request.h new file mode 100644 index 0000000..bf90c68 --- /dev/null +++ b/src/kernel/ipc/request.h @@ -0,0 +1,29 @@ +#ifndef DEF_REQUEST_H +#define DEF_REQUEST_H + +#include "object.h" + +#define A_STILLRUNNING 0 +#define A_NUMBER 1 +#define A_OBJDESCRIPTOR 2 +#define A_VOID 3 + +struct request { + struct object *obj; + struct thread *requester; + uint32_t func, param1, param2, param3; + struct seg_map *shm_cli, *shm_srv; + int answerType; + union { + int num; + struct object* obj; + } answer; +}; + +struct user_request { + uint32_t func, param1, param2, param3; + int hasShm; +}; + +#endif + diff --git a/src/kernel/ipc/shm.c b/src/kernel/ipc/shm.c new file mode 100644 index 0000000..0a0d3ee --- /dev/null +++ b/src/kernel/ipc/shm.c @@ -0,0 +1,56 @@ +#include "shm.h" +#include <mem/mem.h> +#include <mem/seg.h> + +struct segment* shmseg_make(size_t len, struct process* owner) { + struct shmseg *ss = kmalloc(sizeof(struct shmseg)); + struct segment *se = kmalloc(sizeof(struct segment)); + unsigned i; + se->seg_data = ss; + se->mappings = 0; + se->map = shmseg_map; + se->unmap = shmseg_unmap; + se->delete = shmseg_delete; + se->handle_fault = shmseg_handleFault; + ss->len = len; + ss->owner = owner; + ss->frames = kmalloc((len / 0x1000) * sizeof(uint32_t)); + for (i = 0; i < (len / 0x1000); i++) ss->frames[i] = 0; + return se; +} + +struct segment_map *shmseg_map(struct segment *seg, struct page_directory *pagedir, size_t offset) { + struct segment_map *sm = kmalloc(sizeof(struct segment_map)); + sm->start = offset; + sm->len = ((struct shmseg*)(seg->seg_data))->len; + return sm; +} + +void shmseg_unmap(struct segment_map *sm) { + size_t i; + for (i = sm->start; i < sm->start + sm->len; i += 0x1000) { + page_unmap(pagedir_getPage(sm->pagedir, i, 0)); + } +} + +int shmseg_handleFault(struct segment_map *sm, size_t addr, int write) { + struct shmseg *ss = sm->seg->seg_data; + addr &= 0xFFFFF000; + struct page *p = pagedir_getPage(sm->pagedir, addr, 1); + if (p->frame != 0) return 1; + int frame_idx = (addr - sm->start) / 0x1000; + if (ss->frames[frame_idx] == 0) { + ss->frames[frame_idx] = frame_alloc(); + } + page_map(p, ss->frames[frame_idx], 1, 1); + return 0; +} + +void shmseg_delete(struct segment *seg) { + struct shmseg *ss = seg->seg_data; + unsigned i; + for (i = 0; i < (ss->len / 0x1000); i++) { + if (ss->frames[i] != 0) frame_free(ss->frames[i]); + } + kfree(ss->frames); +} diff --git a/src/kernel/ipc/shm.h b/src/kernel/ipc/shm.h new file mode 100644 index 0000000..b409955 --- /dev/null +++ b/src/kernel/ipc/shm.h @@ -0,0 +1,24 @@ +#ifndef DEF_SHM_H +#define DEF_SHM_H + +#include <task/task.h> + +struct shmseg { + size_t len; + uint32_t *frames; + struct process* owner; +}; + +//Shared memory segment stuff +struct segment* shmseg_make(size_t len, struct process* owner); +struct segment_map* shmseg_map(struct segment* seg, struct page_directory *pagedir, size_t offset); +void shmseg_unmap(struct segment_map*); +void shmseg_delete(struct segment *seg); +int shmseg_handleFault(struct segment_map *map, size_t addr, int write); + +//Shared memory syscalls +void shm_create(size_t offset, size_t len); +void shm_delete(size_t offset); + +#endif + diff --git a/src/kernel/lib/mutex.c b/src/kernel/lib/mutex.c new file mode 100644 index 0000000..f3ed11f --- /dev/null +++ b/src/kernel/lib/mutex.c @@ -0,0 +1,23 @@ +#include "mutex.h" +#include <task/task.h> + +static uint32_t atomic_exchange(uint32_t* ptr, uint32_t newval) { + uint32_t r; + asm volatile("xchg (%%ecx), %%eax" : "=a"(r) : "c"(ptr), "a"(newval)); + return r; +} + +void mutex_lock(uint32_t* mutex) { + while (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) { + thread_sleep(1); + } +} + +int mutex_lockE(uint32_t* mutex) { + if (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) return 0; + return 1; +} + +void mutex_unlock(uint32_t* mutex) { + *mutex = MUTEX_UNLOCKED; +} diff --git a/src/kernel/lib/mutex.h b/src/kernel/lib/mutex.h new file mode 100644 index 0000000..2687b30 --- /dev/null +++ b/src/kernel/lib/mutex.h @@ -0,0 +1,15 @@ +#ifndef DEF_MUTEX_H +#define DEF_MUTEX_H + +#include <types.h> + +#define MUTEX_LOCKED 1 +#define MUTEX_UNLOCKED 0 + +//A mutex is just an uint32_t + +void mutex_lock(uint32_t* mutex); //wait for mutex to be free +int mutex_lockE(uint32_t* mutex); //lock mutex only if free, returns !0 if locked, 0 if was busy +void mutex_unlock(uint32_t* mutex); + +#endif diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c index 59f4bdd..bbf4906 100644 --- a/src/kernel/linker/elf.c +++ b/src/kernel/linker/elf.c @@ -21,7 +21,7 @@ thread_entry elf_load(uint8_t *data, struct process* process) { phdr = (struct elf_phdr*)((uint8_t*)(data + ehdr->e_phoff)); for (i = 0; i < ehdr->e_phnum; i++) { if (phdr[i].p_type == PT_LOAD) { - seg_map(simpleseg_make(phdr[i].p_vaddr, phdr[i].p_memsz, (phdr[i].p_flags & PF_W) != 0), process->pagedir); + seg_map(simpleseg_make(phdr[i].p_vaddr, phdr[i].p_memsz, (phdr[i].p_flags & PF_W) != 0), process->pagedir, 0); memcpy((uint8_t*)phdr[i].p_vaddr, data + phdr[i].p_offset, phdr[i].p_filesz); if (phdr[i].p_memsz > phdr[i].p_filesz) { memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_memsz, 0, phdr[i].p_memsz - phdr[i].p_filesz); diff --git a/src/kernel/mem/seg.c b/src/kernel/mem/seg.c index 1452d61..aa71564 100644 --- a/src/kernel/mem/seg.c +++ b/src/kernel/mem/seg.c @@ -1,8 +1,8 @@ #include "seg.h" #include "mem.h" -struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir) { - struct segment_map *sm = seg->map(seg, pagedir); +struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir, size_t offset) { + struct segment_map *sm = seg->map(seg, pagedir, offset); if (sm == 0) return 0; seg->mappings++; sm->seg = seg; @@ -45,7 +45,7 @@ struct segment* simpleseg_make(size_t start, size_t len, int writable) { return se; } -struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir) { +struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset) { struct segment_map *sm = kmalloc(sizeof(struct segment_map)); sm->start = ((struct simpleseg*)(seg->seg_data))->start; sm->len = ((struct simpleseg*)(seg->seg_data))->len; diff --git a/src/kernel/mem/seg.h b/src/kernel/mem/seg.h index 022d38e..4d6660f 100644 --- a/src/kernel/mem/seg.h +++ b/src/kernel/mem/seg.h @@ -8,7 +8,7 @@ struct segment { void* seg_data; int mappings; - struct segment_map* (*map)(struct segment* seg, struct page_directory* pagedir); + struct segment_map* (*map)(struct segment* seg, struct page_directory* pagedir, size_t offset); void (*unmap)(struct segment_map*); void (*delete)(struct segment* seg); int (*handle_fault)(struct segment_map* map, size_t addr, int write); //0 if ok, 1 if segfault @@ -21,7 +21,8 @@ struct segment_map { struct segment_map *next; }; -struct segment_map *seg_map(struct segment* seg, struct page_directory* pagedir); +//parameter offset in seg_map needs not be used +struct segment_map *seg_map(struct segment* seg, struct page_directory* pagedir, size_t offset); void seg_unmap(struct segment_map* map); /// ************************************* SIMPLESEG stuff ***************** @@ -32,7 +33,7 @@ struct simpleseg { }; struct segment* simpleseg_make(size_t start, size_t len, int writable); -struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir); +struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset); void simpleseg_unmap(struct segment_map*); void simpleseg_delete(struct segment *seg); int simpleseg_handleFault(struct segment_map* map, size_t addr, int write); diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c index 72a3d54..cff4ae9 100644 --- a/src/kernel/task/idt.c +++ b/src/kernel/task/idt.c @@ -65,6 +65,7 @@ struct idt_entry idt_entries[256]; struct idt_ptr idt_ptr; static int_callback irq_handlers[16] = {0}; +static struct thread* irq_wakeup[16] = {0}; void idt_isrHandler(struct registers regs) { if ((regs.int_no == 14 && paging_fault(®s) != 0) || regs.int_no != 14) { @@ -80,16 +81,18 @@ void idt_isrHandler(struct registers regs) { } void idt_irqHandler(struct registers regs) { - uint32_t doSwitch = 0; - doSwitch |= (regs.int_no == 32); //IRQ0 = timer + uint32_t doSwitch = (regs.err_code == 0); //IRQ0 = timer if (regs.err_code > 7) { outb(0xA0, 0x20); } outb(0x20, 0x20); + if (irq_wakeup[regs.err_code] != 0) { + irq_wakeup[regs.err_code]->state = TS_RUNNING; + irq_wakeup[regs.err_code] = 0; + doSwitch = 1; + } 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(); } @@ -98,7 +101,7 @@ void idt_syscallHandler(struct registers regs) { if (syscalls[regs.eax] != 0) { syscalls[regs.eax](®s); } else { - PANIC("unhandled syscall"); + monitor_write("Unhandled syscall...\n"); } } @@ -187,5 +190,15 @@ void idt_init() { } void idt_handleIrq(int number, int_callback func) { - irq_handlers[number] = func; + if (number < 16 && number >= 0) { + irq_handlers[number] = func; + } +} + +void idt_waitIrq(int number) { + if (number < 16 && number >= 0 && proc_priv() <= PL_DRIVER) { + irq_wakeup[number] = current_thread; + current_thread->state = TS_WAKEWAIT; + tasking_schedule(); + } } diff --git a/src/kernel/task/idt.h b/src/kernel/task/idt.h index bb89013..ed37eb0 100644 --- a/src/kernel/task/idt.h +++ b/src/kernel/task/idt.h @@ -27,7 +27,8 @@ struct registers { typedef void (*int_callback)(struct registers*); void idt_init(); -void idt_handleIrq(int number, int_callback func); +void idt_handleIrq(int number, int_callback func); //Set IRQ handler +void idt_waitIrq(int number); //ask current thread to wait for IRQ #endif diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c index 8195dd0..752864c 100644 --- a/src/kernel/task/syscall.c +++ b/src/kernel/task/syscall.c @@ -14,6 +14,7 @@ CALL0V(tasking_switch, schedule_sc); CALL1V(thread_sleep, thread_sleep_sc); CALL1V(process_exit, process_exit_sc); CALL1(monitor_write, printk_sc); +CALL1V(idt_waitIrq, irq_wait_sc); static void thread_new_sc(struct registers* r) { thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx); @@ -26,4 +27,5 @@ int_callback syscalls[] = { process_exit_sc, printk_sc, thread_new_sc, + irq_wait_sc, 0 }; diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c index 8cdf7b3..622eaa1 100644 --- a/src/kernel/task/task.c +++ b/src/kernel/task/task.c @@ -88,6 +88,10 @@ void tasking_switch() { : : "r"(current_thread->ebp), "r"(current_thread->esp), "r"(current_thread->eip)); } +void tasking_schedule() { + asm volatile("int $64" : : "a"(1)); +} + void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablephysical) { if (idx < 896) return; struct process* it = processes; @@ -121,7 +125,12 @@ void thread_sleep(uint32_t msecs) { if (current_thread == 0) return; current_thread->state = TS_SLEEPING; current_thread->timeWait = timer_time() + msecs; - asm volatile("int $64" : : "a"(1)); + tasking_schedule(); +} + +int proc_priv() { + if (current_thread == 0) return PL_UNKNOWN; + return current_thread->process->privilege; } void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h @@ -167,7 +176,10 @@ void process_exit(uint32_t retval) { 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; + if (t->state == TS_SLEEPING && timer_time() >= t->timeWait) { + t->state = TS_RUNNING; + return 1; + } return 0; } @@ -220,7 +232,7 @@ struct thread *thread_new(struct process *proc, thread_entry entry_point, void * if (proc->privilege >= PL_SERVICE) { //We are running in user mode proc->stacksBottom -= USER_STACK_SIZE; - t->userStack_seg = seg_map(simpleseg_make(proc->stacksBottom, USER_STACK_SIZE, 1), proc->pagedir); + t->userStack_seg = seg_map(simpleseg_make(proc->stacksBottom, USER_STACK_SIZE, 1), proc->pagedir, 0); } t->kernelStack_addr = kmalloc(KSTACKSIZE); diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index d363333..dd5461e 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -7,8 +7,9 @@ #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) +#define TS_WAKEWAIT 2 //Waiting to be waked up by something precise (thread currently blocked) +#define PL_UNKNOWN 4 #define PL_USER 3 #define PL_SERVICE 2 #define PL_DRIVER 1 @@ -47,10 +48,12 @@ extern struct thread *current_thread; void tasking_init(); void tasking_switch(); +void tasking_schedule(); void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablePhysical); uint32_t tasking_handleException(struct registers *regs); void thread_sleep(uint32_t msecs); +int proc_priv(); //Returns current privilege level void thread_exit(); void process_exit(uint32_t retval); struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data); |