summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/syscalls.txt1
-rw-r--r--src/kernel/Makefile3
-rw-r--r--src/kernel/ipc/object.h26
-rw-r--r--src/kernel/ipc/request.h29
-rw-r--r--src/kernel/ipc/shm.c56
-rw-r--r--src/kernel/ipc/shm.h24
-rw-r--r--src/kernel/lib/mutex.c23
-rw-r--r--src/kernel/lib/mutex.h15
-rw-r--r--src/kernel/linker/elf.c2
-rw-r--r--src/kernel/mem/seg.c6
-rw-r--r--src/kernel/mem/seg.h7
-rw-r--r--src/kernel/task/idt.c25
-rw-r--r--src/kernel/task/idt.h3
-rw-r--r--src/kernel/task/syscall.c2
-rw-r--r--src/kernel/task/task.c18
-rw-r--r--src/kernel/task/task.h5
-rw-r--r--src/library/grapes/syscall.c4
-rw-r--r--src/library/grapes/syscall.h1
18 files changed, 231 insertions, 19 deletions
diff --git a/doc/syscalls.txt b/doc/syscalls.txt
index 530fbab..baa537e 100644
--- a/doc/syscalls.txt
+++ b/doc/syscalls.txt
@@ -11,5 +11,6 @@ id=eax Name Parameters Description
4 printk ebx: addr of a string Print a message to screen
5 thread_new ebx: entry point Creates a new thread
ecx: data pointer
+ 6 irq_wait ebx: irq number Waits for an IRQ (requires privilege PL_DRIVER)
If a processes wishes to exit with an error code, it HAS to use process_exit. thread_exit will do nothing.
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(&regs) != 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](&regs);
- } 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](&regs);
} 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);
diff --git a/src/library/grapes/syscall.c b/src/library/grapes/syscall.c
index a00d9e8..38adc01 100644
--- a/src/library/grapes/syscall.c
+++ b/src/library/grapes/syscall.c
@@ -29,3 +29,7 @@ void printk(char* str) {
void thread_new(void (*entry)(void*), void *data) {
call(5, (unsigned)entry, (unsigned)data, 0, 0, 0);
}
+
+void irq_wait(int number) {
+ call(6, number, 0, 0, 0, 0);
+}
diff --git a/src/library/grapes/syscall.h b/src/library/grapes/syscall.h
index e385761..d2f80e5 100644
--- a/src/library/grapes/syscall.h
+++ b/src/library/grapes/syscall.h
@@ -7,5 +7,6 @@ void thread_sleep(int time);
void process_exit(int retval);
void printk(char* str);
void thread_new(void (*entry)(void*), void *data);
+void irq_wait(int number);
#endif