summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/objects.txt181
-rw-r--r--doc/roadmap.txt1
-rw-r--r--doc/syscalls.txt64
-rw-r--r--src/common/include/sched.h1
-rw-r--r--src/common/include/string.h1
-rw-r--r--src/common/include/tce/Folder_common.h10
-rw-r--r--src/common/include/tce/Object_common.h10
-rw-r--r--src/common/string.c7
-rw-r--r--src/kernel/Makefile3
-rw-r--r--src/kernel/Object/Folder_if.c8
-rw-r--r--src/kernel/Object/Folder_if.h15
-rw-r--r--src/kernel/Object/Object.c188
-rw-r--r--src/kernel/Object/Object.h78
-rw-r--r--src/kernel/Object/VirtualFolder_cl.c96
-rw-r--r--src/kernel/Object/VirtualFolder_cl.h30
-rw-r--r--src/kernel/core/kmain.c19
-rw-r--r--src/kernel/core/monitor.h3
-rw-r--r--src/kernel/lib/earray.c156
-rw-r--r--src/kernel/lib/earray.h40
-rw-r--r--src/kernel/lib/std.c8
-rw-r--r--src/kernel/lib/std.h2
-rw-r--r--src/kernel/linker/elf.c2
-rw-r--r--src/kernel/mem/paging.c13
-rw-r--r--src/kernel/task/idt.c12
-rw-r--r--src/kernel/task/syscall.c70
-rw-r--r--src/kernel/task/syscall.h2
-rw-r--r--src/kernel/task/task.c41
-rw-r--r--src/kernel/task/task.h4
-rw-r--r--src/user/lib/Makefile3
-rw-r--r--src/user/lib/include/stdio.h2
-rw-r--r--src/user/lib/include/tce/Folder.h12
-rw-r--r--src/user/lib/include/tce/Object.h17
-rw-r--r--src/user/lib/std/stdio.c1
-rw-r--r--src/user/lib/tce/Folder.c24
-rw-r--r--src/user/lib/tce/syscall.c48
-rw-r--r--src/user/test/main.c69
36 files changed, 1132 insertions, 109 deletions
diff --git a/doc/objects.txt b/doc/objects.txt
new file mode 100644
index 0000000..956ad74
--- /dev/null
+++ b/doc/objects.txt
@@ -0,0 +1,181 @@
+Let me say this in french. Sorry for english-only-speaking people, i'll translate someday.
+
+L'idée principale motivant le développement de T/CE est celle d'un nouveau protocole entre le
+noyau et les applications utilisateur.
+
+Les objets du systèmes sont accessibles sous la forme d'un système de fichiers dans lequel on
+navigue, sauf que les objets sont en fait bien plus que de simples fichiers.
+
+Ce protocole se base sur trois définitions fondamentales :
+-- Interfaces :
+Une interface est un ensemble de définitions (de prototypes, donc) de méthodes qui
+peuvent être implémentées par un objet du système.
+Parmi les méthodes, il y a des méthodes publiques, faites pour être appellées par les
+applications utilisateurs, et des méthodes internes au noyau.
+-- Classe :
+Une classe, c'est un regroupement d'interfaces avec leur implémentation spécifique.
+-- Objet :
+Un objet du système est d'une classe précise, et correspond donc à un des objets gérés
+par le code de cette classe. On peut appeller toutes les méthodes des interfaces implémentées
+par la classe de l'objet sur cet objet.
+
+Ce n'est peut-être pas très clair, alors illustrons :
+
+Interface : Keyboard
+- OutputToConsole(Console)
+Interface : Console
+- SetActiveVT (VirtualTerminal)
+- NewBufferedVT (char*) // crée un nouveau terminal virtuel - char* = le nom
+- (internal) receiveKeyboardInput(int)
+- (internal) repaint(char*)
+- (internal) write(int, char*)
+Interface : VirtualTerminal
+- Read(int, char*)
+- Write(int, char*)
+- (internal) receiveKeyboardInput(int)
+- (internal) outputToConsole(Console, int, int) // int, int = dimensions de la console
+
+Classe : PS2Keyboard
+- Garde en mémoire la console à qui il envoie les données
+- Quand une touche est pressée/relâchée, appeller receiveKeyboardInput sur cette console
+- Implémenter la méthode OutputToConsole pour changer la console à qui les données sont envoyées
+Classe : TextConsole
+- Implémente la gestion de l'écran texte VGA de base
+- Garde en mémoire le VirtualTerminal actif
+- Transmet l'entrée clavier au VirtualTerminal actif
+- Lorsqu'on lui demande de changer le VT actif :
+ il signale à l'ancien VT de ne plus émettre,
+ il signale au nouveau VT d'émettre vers cette console
+ et spécifie au nouveau VT la bonne dimension d'écran
+Classe : BufferedVirtualTerminal
+- Il garde en mémoire LA Console vers laquelle il doit émettre, ainsi que ses dimensions
+- Garde un buffer de tout ce qui passe sur la console, et un buffer de l'écran actif.
+- Lorsqu'il reçoit une entrée clavier, la bufferise, puis la restitue lors du prochain appel à Read
+- Lorsqu'on écrit quelque chose dessus avec Write, il le garde dans son buffer
+ et le donne aussi au terminal virtuel de sortie, s'il y en a un
+
+
+Implémentation :
+
+// Structures
+
+struct Interface {
+ char* name;
+ int method_count;
+ int public_method_count;
+
+ NumberedMethod numberedMethods[];
+ int methodNumbers[];
+};
+
+struct NumberedMethod {
+ Interface *iface;
+ int numberInIface;
+};
+
+type MethodPtr (function pointer type);
+
+struct InterfaceImpl {
+ Interface *interface;
+ MethodPtr methods[];
+};
+
+struct Class {
+ char* name;
+ MethodPtr *findChild;
+ InterfaceImpl interfaces[]; //zero-terminated list
+};
+
+struct Object {
+ Class *class;
+ void *data;
+};
+
+// setup code
+
+void Class_setup(Class* class) {
+ for (int i = 0; class->interfaces[i] != 0; i++) {
+ Interface_setup(class->interfaces[i]->interface)
+ }
+}
+
+ExpandableTable<NumberedMethod*> allMethods;
+
+void Interface_setup(Interface* iface) {
+ if (iface->numberedMethods != 0) return;
+ iface->numberedMethods = malloc(iface->method_count * sizeof(NumberedMethod));
+ iface->methodNumbers = malloc(iface->method_count * sizeof(int));
+
+ for (int i = 0; i < iface->method_count; i++) {
+ iface->methodNumbers[i] = allMethods.register(&impl->numberedMethods[i])
+ iface->numberedMethods[i]->numberInIface = i;
+ iface->numberedMethods[i]->ptr = impl->methods[i];
+ }
+}
+
+void Object_callByNumber(Object *obj, int number, params...) {
+ NumberedMethod *method = allMethods.get(number);
+ for (int i = 0; obj->class->interfaces[i] != 0; i++) {
+ InterfaceImpl impl = obj->class->interfaces[i];
+ if (method->iface == impl->interface) {
+ MethodPtr fct = impl->methods[method->numberInIface];
+ return fct (params...)
+ }
+ }
+ return E_NOT_IMPLEMENTED;
+}
+
+// Exemple
+
+struct ConsoleMethods {
+ MethodPtr SetActiveVT;
+ MethodPtr NewBufferedVT;
+ MethodPtr receiveKeyboardInput;
+ MethodPtr repaint;
+ MethodPtr write;
+};
+
+Interface ConsoleIface = {
+ name: "Console",
+ method_count: 5,
+ public_method_count: 2,
+
+ numberedMethods: 0, methodNumbers: 0, // internal
+};
+
+ConsoleMethods TextConsole_as_Console = {
+ SetActiveVT: TextConsole_SetActiveVT,
+ NewBufferedVT: TextConsole_NewBufferedVT,
+ receiveKeyboardInput: TextConsole_receiveKeyboardInput,
+ repaint: TextConsole_repaint,
+ write: TextConsole_write,
+};
+
+Class TextConsoleClass = {
+ name: "TextConsole",
+ findChild: Console_findChild,
+ interfaces: {
+ { ConsoleIface, (MethodPtr*)TextConsole_as_Console },
+ 0
+ },
+};
+
+struct TextConsole {
+ Object object;
+
+ //... data ...
+};
+
+// Other example
+
+struct FolderMethods {
+ MethodPtr GetChildList;
+};
+
+Interface FolderIface = {
+ name: "Folder",
+ method_count: 1,
+ public_method_count: 1,
+
+ numberedMethods: 0, methodNumbers: 0, // internal
+};
diff --git a/doc/roadmap.txt b/doc/roadmap.txt
index dabae61..835b26d 100644
--- a/doc/roadmap.txt
+++ b/doc/roadmap.txt
@@ -4,7 +4,6 @@ Stuff to do :
- remove useless code from grapes
- clean up existing code
-- reorganize directories
- document the new syscall (Interface/Class/Object) system
- basic implementation
diff --git a/doc/syscalls.txt b/doc/syscalls.txt
index c94db19..d37d822 100644
--- a/doc/syscalls.txt
+++ b/doc/syscalls.txt
@@ -1,25 +1,51 @@
-Syscalls pass by int64. The identifier of the called function is in eax, parameters
-are in ebx, ecx, edx, esi, edi.
+See objects.txt for info about the object model in the kernel.
+
+Syscalls are called with int64.
+
+== Calls to objects
+
+When eax != 0, the value of eax is the ID of an object in the process's handle list.
+In that case, ebx is the number of the method to be called,
+and ecx, edx, esi, edi are the parameters.
+
+
+== Calls to other stuff
+
+When int64 is called with eax = 0, it's identified as a normal syscall from the following list:
+
+The identifier of the called function is in ebx, parameters are in ecx, edx, esi, edi.
Syscall list :
-id=eax Name Parameters Description
- 0 thread_exit none Signal kernel that current thread has finished
- 1 schedule none Switch to next thread (might be the current one)
- 2 thread_sleep ebx: time (int) msecs Tell kernel to put current thread to sleep
- 3 process_exit ebx: return value (int) Tell kernel to end current process, cleaning up everything
- 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
- edx: stack pointer
- 6 irq_wait ebx: irq number Waits for an IRQ (requires privilege PL_DRIVER)
- 7 proc_priv none Returns current process privilege level
-
- 8 sbrk ebx: size Allocates some memory
- 9 brk ebx: new_end Allocates/frees some memory
-
- 10 mmap (see linux specs)
- 11 munmap (see linux specs)
+id=ebx Name Parameters Description
+ 1 thread_exit none Signal kernel that current thread has finished
+ 2 schedule none Switch to next thread (might be the current one)
+ 3 thread_sleep ecx: time (int) msecs Tell kernel to put current thread to sleep
+ 4 process_exit ecx: return value (int) Tell kernel to end current process, cleaning up everything
+ 5 printk ecx: addr of a string Print a message to screen
+ 6 thread_new ecx: entry point Creates a new thread
+ edx: data pointer
+ esi: stack pointer
+ 7 irq_wait ecx: irq number Waits for an IRQ (requires privilege PL_DRIVER)
+ 8 proc_priv none Returns current process privilege level
+
+ 9 sbrk ecx: size Allocates some memory
+ 10 brk ecx: new_end Allocates/frees some memory
+
+ 11 mmap (see linux specs) NOT IMPLEMENTED
+ 12 munmap (see linux specs) NOT IMPLEMENTED
+
+ 13
+ ... UNUSED (yet)
+ 19
+
+ 20 open ecx: ptr to path str Looks for an object in the hierarchy, returns a handle
+ 21 open_relative ecx: ptr to path str Looks for an object using a given root object
+ edx: base object handle
+ 22 close ecx: object handle Close handle to an object
+ 23 get_methods ecx: ptr to iface name Gets the numbers of the methods in an interface
+ str
+ edx: ptr to where to store
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/common/include/sched.h b/src/common/include/sched.h
index 0f8f8f4..1012116 100644
--- a/src/common/include/sched.h
+++ b/src/common/include/sched.h
@@ -7,6 +7,7 @@
#define MUTEX_UNLOCKED 0
//A mutex is just an uint32_t
+typedef uint32_t mutex_t;
int 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
diff --git a/src/common/include/string.h b/src/common/include/string.h
index a41459e..7d0bf20 100644
--- a/src/common/include/string.h
+++ b/src/common/include/string.h
@@ -6,7 +6,6 @@
int strlen(const char *str);
char *strcpy(char *dest, const char *src);
-// char *strdup(const char *src); // uses malloc, that's bad
char *strchr(const char *str, char c);
char *strcat(char *dest, const char *src);
int strcmp(const char *s1, const char *s2);
diff --git a/src/common/include/tce/Folder_common.h b/src/common/include/tce/Folder_common.h
new file mode 100644
index 0000000..b1037dd
--- /dev/null
+++ b/src/common/include/tce/Folder_common.h
@@ -0,0 +1,10 @@
+#ifndef DEF_TCE_FOLDER_H
+#define DEF_TCE_FOLDER_H
+
+#define FILENAME_MAX_LEN 256
+
+struct FolderMethods {
+ int GetChildNameAt;
+};
+
+#endif
diff --git a/src/common/include/tce/Object_common.h b/src/common/include/tce/Object_common.h
new file mode 100644
index 0000000..70a034e
--- /dev/null
+++ b/src/common/include/tce/Object_common.h
@@ -0,0 +1,10 @@
+#ifndef DEF_OBJECT_U_H
+#define DEF_OBJECT_U_H
+
+#define E_INVALID -2
+#define E_BAD_HANDLE -3
+#define E_NOT_IMPLEMENTED -4
+#define E_NOT_PUBLIC -5
+#define E_NOT_FOUND -6
+
+#endif
diff --git a/src/common/string.c b/src/common/string.c
index 120fd5d..4c2dba8 100644
--- a/src/common/string.c
+++ b/src/common/string.c
@@ -20,13 +20,6 @@ char *strcpy(char *dest, const char *src) {
return (char*)src;
}
-/*char *strdup(const char *src) {
- char* ret = malloc(strlen(src) + 1);
- if (ret == NULL) return ret;
- strcpy(ret, src);
- return ret;
-}*/
-
char *strcat(char *dest, const char *src) {
char *dest2 = dest;
dest2 += strlen(dest) - 1;
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
index 6060911..485a02e 100644
--- a/src/kernel/Makefile
+++ b/src/kernel/Makefile
@@ -2,8 +2,9 @@ Out = kernel.elf
Obj = 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 task/sched.o \
- lib/bitset.o lib/std.o \
+ lib/bitset.o lib/std.o lib/earray.o \
mem/mem.o mem/paging.o mem/gdt.o mem/_dlmalloc.o mem/seg.o \
+ Object/Object.o Object/Folder_if.o Object/VirtualFolder_cl.o \
linker/elf.o
ExtObj = $(SrcPath)/common/_common.o
diff --git a/src/kernel/Object/Folder_if.c b/src/kernel/Object/Folder_if.c
new file mode 100644
index 0000000..81fd6ad
--- /dev/null
+++ b/src/kernel/Object/Folder_if.c
@@ -0,0 +1,8 @@
+#include "Folder_if.h"
+
+Interface FolderIface = {
+ "Folder", // name
+ 2, // method count
+ 1, // public method count
+ 0, 0 // internal
+};
diff --git a/src/kernel/Object/Folder_if.h b/src/kernel/Object/Folder_if.h
new file mode 100644
index 0000000..8f1db11
--- /dev/null
+++ b/src/kernel/Object/Folder_if.h
@@ -0,0 +1,15 @@
+#ifndef DEF_FOLDER_IF_H
+#define DEF_FOLDER_IF_H
+
+#include "Object.h"
+#include <tce/Folder_common.h>
+
+typedef struct _FolderMethods {
+ MethodPtr GetChildNameAt;
+ MethodPtr addChild;
+} FolderMethods;
+
+extern Interface FolderIface;
+
+#endif
+
diff --git a/src/kernel/Object/Object.c b/src/kernel/Object/Object.c
new file mode 100644
index 0000000..3af8fff
--- /dev/null
+++ b/src/kernel/Object/Object.c
@@ -0,0 +1,188 @@
+#include "Object.h"
+
+#include "VirtualFolder_cl.h"
+#include <task/task.h>
+#include <core/sys.h>
+#include <core/monitor.h>
+
+#include <lib/earray.h>
+
+struct earray numberedMethods;
+struct earray interfaces;
+
+void setup_object_system() {
+ numberedMethods.ref_vect_init_len = 32;
+ numberedMethods.vect_len = 256;
+ numberedMethods.data = 0;
+ earray_init(&numberedMethods);
+
+ interfaces.ref_vect_init_len = 32;
+ interfaces.vect_len = 32;
+ interfaces.data = 0;
+ earray_init(&interfaces);
+
+ Class_setup(&VirtualFolderClass);
+
+ rootObject = VirtualFolder_new();
+ deviceListObject = VirtualFolder_new();
+ VirtualFolder_addChild(rootObject, 0, ".dev", deviceListObject, 0, 0);
+}
+
+void Class_setup(Class *_class) {
+ monitor_write("\n * Setup class '");
+ monitor_write(_class->name);
+ monitor_write("'... ");
+
+ int i;
+ for (i = 0; _class->interfaces[i].interface != 0; i++) {
+ Interface_setup(_class->interfaces[i].interface);
+ }
+}
+
+void Interface_setup(Interface *iface) {
+ int i;
+
+ monitor_write("\n - Setup interface '");
+ monitor_write(iface->name);
+ monitor_write("' :");
+
+ if (iface->numberedMethods != 0) return;
+
+ earray_add(&interfaces, iface);
+
+ iface->numberedMethods = kmalloc(iface->method_count * sizeof(NumberedMethod));
+ iface->methodNumbers = kmalloc(iface->method_count * sizeof(int));
+
+ for (i = 0; i < iface->method_count; i++) {
+ iface->numberedMethods[i].iface = iface;
+ iface->numberedMethods[i].numberInIface = i;
+ iface->methodNumbers[i] = earray_add(&numberedMethods, &iface->numberedMethods[i]);
+ monitor_write(" #"); monitor_writeDec(iface->methodNumbers[i]);
+ }
+}
+
+MethodPtr *Class_getInterfaceImpl(Class *_class, Interface *iface) {
+ int i;
+ for (i = 0; _class->interfaces[i].interface != 0; i++) {
+ if (_class->interfaces[i].interface == iface) {
+ return _class->interfaces[i].methods;
+ }
+ }
+ return 0;
+}
+
+Object* Object_get(Object *parent, char *path) {
+ char* member = path;
+ Object *object = parent;
+
+ while (*path != 0 && object != 0) {
+ if (*path == '/') {
+ if (member == path) {
+ member++;
+ path++;
+ } else {
+ *path = 0;
+ if (object->_class->findChild != 0) {
+ object = object->_class->findChild(object, member);
+ } else {
+ object = 0;
+ }
+ path++;
+ member = path;
+ }
+ } else {
+ path++;
+ }
+ }
+ if (object != 0 && member != path) {
+ if (object->_class->findChild != 0) {
+ object = object->_class->findChild(object, member);
+ } else {
+ object = 0;
+ }
+ }
+
+ return object;
+}
+
+// SYSCALLS
+
+int open(char* name) {
+ ASSERT(current_process != 0);
+
+ Object *obj = Object_get(rootObject, name);
+ if (obj == 0) return E_NOT_FOUND;
+ obj->handles++;
+ return earray_add(&current_process->handles, obj);
+}
+
+int open_relative(char* name, int root_handle) {
+ ASSERT(current_process != 0);
+
+ Object *parent = read_handle(current_process, root_handle);
+ if (parent == 0) return E_BAD_HANDLE;
+ Object *obj = Object_get(parent, name);
+ if (obj == 0) return E_NOT_FOUND;
+ if (obj->_class->open != 0) {
+ int r = obj->_class->open(obj, current_process);
+ if (r != 0) return r;
+ }
+ obj->handles++;
+ return earray_add(&current_process->handles, obj);
+}
+
+void close(size_t handle) {
+ ASSERT(current_process != 0);
+
+ Object *obj = read_handle(current_process, handle);
+ if (obj == 0) return;
+ obj->handles--;
+ if (obj->_class->closed != 0) obj->_class->closed(obj);
+ earray_set(&current_process->handles, handle, 0);
+}
+
+int get_methods(char* iface_name, int* whereto) {
+ int i = 0;
+ Interface *iface = 0, *tmp;
+ for (i = 0; i < interfaces.elements; i++) {
+ tmp = earray_at(&interfaces, i);
+ if (tmp != 0) {
+ if (strcmp(tmp->name, iface_name) == 0) {
+ iface = tmp;
+ break;
+ }
+ }
+ }
+ if (iface == 0) return E_NOT_FOUND;
+ for (i = 0; i < iface->public_method_count; i++) {
+ whereto[i] = iface->methodNumbers[i];
+ }
+ return iface->public_method_count;
+}
+
+Object* read_handle(struct process *proc, size_t handle) {
+ if (proc == 0) return (Object*)handle;
+ return earray_at(&proc->handles, handle);
+}
+
+int do_method_call_2(int handle, int method, size_t a, size_t b, size_t c, size_t d) {
+ ASSERT(current_process != 0)
+
+ Object *obj = read_handle(current_process, handle);
+ if (obj == 0) return E_BAD_HANDLE;
+
+ NumberedMethod *nm = earray_at(&numberedMethods, method);
+ if (nm == 0) return E_NOT_IMPLEMENTED;
+ if (nm->numberInIface >= nm->iface->public_method_count) return E_NOT_PUBLIC;
+
+ MethodPtr* m = Class_getInterfaceImpl(obj->_class, nm->iface);
+ if (m == 0) return E_NOT_IMPLEMENTED;
+ MethodPtr p = m[nm->numberInIface];
+ ASSERT(p != 0);
+
+ return p(obj, current_process, a, b, c, d);
+}
+
+void do_method_call(struct registers *regs) {
+ regs->eax = do_method_call_2(regs->eax, regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi);
+}
diff --git a/src/kernel/Object/Object.h b/src/kernel/Object/Object.h
new file mode 100644
index 0000000..1b0daec
--- /dev/null
+++ b/src/kernel/Object/Object.h
@@ -0,0 +1,78 @@
+#ifndef DEF_INTERFACE_H
+#define DEF_INTERFACE_H
+
+#include <types.h>
+#include <task/task.h>
+
+#include <tce/Object_common.h>
+
+struct _Object;
+struct _NumberedMethod;
+
+typedef struct _Interface {
+ char* name;
+ int method_count;
+ int public_method_count;
+
+ struct _NumberedMethod *numberedMethods;
+ int *methodNumbers;
+} Interface;
+
+typedef struct _NumberedMethod {
+ Interface *iface;
+ int numberInIface;
+} NumberedMethod;
+
+typedef int (*MethodPtr)(struct _Object* object, struct process* process, size_t a, size_t b, size_t c, size_t d);
+typedef struct _Object* (*FindChildPtr)(struct _Object *object, const char* name);
+typedef int (*OpenPtr)(struct _Object *object, struct process *process);
+typedef void (*ClosedPtr)(struct _Object *object);
+typedef void (*DeletePtr)(struct _Object *object);
+
+typedef struct _InterfaceImpl {
+ Interface *interface;
+ MethodPtr *methods;
+} InterfaceImpl;
+
+// ==
+
+typedef struct _Class {
+ char *name;
+ FindChildPtr findChild;
+ OpenPtr open; // optionnal - if 0, always success
+ ClosedPtr closed; // optionnal
+ DeletePtr deleted; // optionnal but should be implemented
+ InterfaceImpl interfaces[]; // zero-terminated list
+} Class;
+
+typedef struct _Object {
+ Class *_class;
+ void *data;
+ int handles; // reference counter
+} Object;
+
+//
+
+void setup_object_system();
+
+void Class_setup(Class* _class);
+void Interface_setup(Interface* iface);
+
+MethodPtr* Class_getInterfaceImpl(Class *_class, Interface *iface);
+
+Object* Object_get(Object *parent, char *path);
+
+Object *rootObject, *deviceListObject;
+
+// syscalls
+int open(char* name);
+int open_relative(char* name, int root_handle);
+void close(size_t handle);
+int get_methods(char* iface_name, int* whereto);
+
+Object* read_handle(struct process *proc, size_t handle);
+void do_method_call(struct registers *regs);
+
+
+#endif
+
diff --git a/src/kernel/Object/VirtualFolder_cl.c b/src/kernel/Object/VirtualFolder_cl.c
new file mode 100644
index 0000000..98641dd
--- /dev/null
+++ b/src/kernel/Object/VirtualFolder_cl.c
@@ -0,0 +1,96 @@
+#include <string.h>
+
+#include <core/monitor.h>
+#include <core/sys.h>
+
+#include "VirtualFolder_cl.h"
+
+MethodPtr _VirtualFolderMethodsAsFolder[] = {
+ &VirtualFolder_GetChildNameAt,
+ &VirtualFolder_addChild,
+ 0
+ };
+Class VirtualFolderClass = {
+ "VirtualFolder",
+ VirtualFolder_findChild, 0, 0, VirtualFolder_delete,
+ {
+ { &FolderIface, &_VirtualFolderMethodsAsFolder
+ },
+ { 0, { 0 } }
+ }
+};
+
+Object *VirtualFolder_new() {
+ struct _VirtualFolder *f = kmalloc(sizeof(struct _VirtualFolder));
+ f->obj.data = f;
+ f->obj._class = &VirtualFolderClass;
+ f->obj.handles = 0;
+
+ f->children.ref_vect_init_len = 32;
+ f->children.vect_len = 64;
+ f->children.data = 0;
+ earray_init(&f->children);
+
+ struct _VirtualFolder_child *fc = kmalloc(sizeof(struct _VirtualFolder));
+ fc->name = ".";
+ fc->obj = &f->obj;
+
+ earray_add(&f->children, fc);
+ f->child_count = 1;
+
+ return &f->obj;
+}
+
+void VirtualFolder_delete(Object *o) {
+ struct _VirtualFolder *f = o->data;
+ int i;
+ for (i = 1; i < f->child_count; i++) {
+ struct _VirtualFolder_child *child = earray_at(&f->children, i);
+ if (child->obj->_class->deleted != 0) child->obj->_class->deleted(child->obj);
+ kfree(child);
+ }
+ kfree(earray_at(&f->children, 0)); // self-reference, "."
+ earray_free(&f->children);
+ kfree(f);
+}
+
+Object *VirtualFolder_findChild(Object* object, const char* name) {
+ struct _VirtualFolder *f = object->data;
+ int i;
+ for (i = 1; i < f->child_count; i++) {
+ struct _VirtualFolder_child *child = earray_at(&f->children, i);
+ if (strcmp(name, child->name) == 0) return child->obj;
+ }
+ return 0;
+}
+
+
+int VirtualFolder_GetChildNameAt(Object *object, struct process *process, size_t a, size_t b, size_t c, size_t d) {
+ struct _VirtualFolder *f = object->data;
+ if (a >= f->child_count) return E_NOT_FOUND;
+ struct _VirtualFolder_child *child = earray_at(&f->children, a);
+ strcpy((char*)b, child->name);
+ return strlen(child->name);
+}
+
+int VirtualFolder_addChild(Object *object, struct process *process, size_t a, size_t b, size_t c, size_t d) {
+ ASSERT(process == 0); // this is done in kernel land
+ struct _VirtualFolder *f = object->data;
+
+ if (b == 0) return E_INVALID;
+
+ struct _VirtualFolder_child *fc = kmalloc(sizeof(struct _VirtualFolder));
+ fc->name = strdup((char*)a);
+ fc->obj = (Object*)b;
+
+ if (strlen(fc->name) >= FILENAME_MAX_LEN) {
+ fc->name[FILENAME_MAX_LEN] = 0;
+ }
+
+ // THIS SHOULD'NT BE DONE LIKE THIS, IT'S TO CHECK OUR CODE WORKS!
+ ASSERT(earray_add(&f->children, fc) == f->child_count);
+
+ f->child_count++;
+
+ return 0;
+}
diff --git a/src/kernel/Object/VirtualFolder_cl.h b/src/kernel/Object/VirtualFolder_cl.h
new file mode 100644
index 0000000..fac697d
--- /dev/null
+++ b/src/kernel/Object/VirtualFolder_cl.h
@@ -0,0 +1,30 @@
+#ifndef DEF_VIRTUALFOLDER_CL_H
+#define DEF_VIRTUALFOLDER_CL_H
+
+#include "Folder_if.h"
+
+#include <lib/earray.h>
+
+extern Class VirtualFolderClass;
+
+struct _VirtualFolder {
+ Object obj;
+
+ int child_count;
+ struct earray children;
+};
+
+struct _VirtualFolder_child {
+ char* name;
+ Object *obj;
+};
+
+Object *VirtualFolder_new();
+void VirtualFolder_delete(Object* obj);
+
+Object* VirtualFolder_findChild(Object* object, const char* name);
+
+int VirtualFolder_GetChildNameAt(Object *object, struct process* process, size_t a, size_t b, size_t c, size_t d);
+int VirtualFolder_addChild(Object *object, struct process* process, size_t a, size_t b, size_t c, size_t d);
+
+#endif
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 8c36b54..3401107 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -12,6 +12,8 @@
#include <mem/mem.h>
#include <linker/elf.h>
+#include <Object/Object.h>
+
/* The kernel's main procedure. This function is called in loader_.asm.
This function calls the initializer functions for all system parts.
It then loads the modules the kernel was given by the bootloader.
@@ -36,12 +38,13 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) {
monitor_clear();
+ monitor_write(" -> This is ");
monitor_write(K_OS_NAME);
monitor_write(" version ");
monitor_write(K_OS_VER);
monitor_write(" codename '");
monitor_write(K_OS_CODENAME);
- monitor_write("' starting up :\n");
+ monitor_write("', now starting up :\n");
idt_init();
@@ -52,27 +55,27 @@ void kmain(struct multiboot_info_t* mbd, int32_t magic) {
gdt_init();
paging_cleanup();
- //kheap_init();
timer_init(30);
tasking_init();
+
+ setup_object_system();
- monitor_write("\n\nLoading modules :\n");
for (i = 0; i < mbd->mods_count; i++) {
- monitor_write(" * ");
+ monitor_write("\n * Load multiboot module '");
monitor_write((char*)mods[i].string);
if (elf_check((uint8_t*)mods[i].mod_start)) {
- monitor_write(" : Invalid ELF file\n");
+ monitor_write("' : Invalid ELF file");
} else {
struct process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_USER);
if (pr == 0) {
- monitor_write(" : Error loading\n");
+ monitor_write("' : Error loading");
} else {
- monitor_write(" : OK, pid="); monitor_writeDec(pr->pid); monitor_write("\n");
+ monitor_write("' : OK, pid="); monitor_writeDec(pr->pid);
}
}
}
- monitor_write("Modules now RULE THE WORLD !\n\n");
+ monitor_write("\nUserland processes now RULE THE WORLD !\n\n");
sti();
schedule();
PANIC("Should never happen. Something probably went wrong with multitasking.");
diff --git a/src/kernel/core/monitor.h b/src/kernel/core/monitor.h
index bb8e16e..f7ca453 100644
--- a/src/kernel/core/monitor.h
+++ b/src/kernel/core/monitor.h
@@ -11,11 +11,12 @@ void monitor_writeDec(uint32_t v);
#define NL monitor_put('\n');
#define TAB monitor_put('\t');
+#define WS monitor_put(' ');
#define WHERE { monitor_write("(kernel:"); \
monitor_write(__FILE__); \
monitor_write(":"); \
monitor_writeDec(__LINE__); \
- monitor_write(")\t"); }
+ monitor_write(") "); }
#endif
diff --git a/src/kernel/lib/earray.c b/src/kernel/lib/earray.c
new file mode 100644
index 0000000..a17e823
--- /dev/null
+++ b/src/kernel/lib/earray.c
@@ -0,0 +1,156 @@
+#include "earray.h"
+
+#include <mem/mem.h>
+#include <core/sys.h>
+
+void earray_init(struct earray *array) {
+ int i;
+
+ if (array->data != 0) return;
+
+ array->ref_vect_len = array->ref_vect_init_len;
+ array->elements = 0;
+ array->mutex = MUTEX_UNLOCKED;
+
+ array->data = kmalloc(array->ref_vect_len * sizeof(void***));
+
+ for (i = 0; i < array->ref_vect_len; i++) {
+ array->data[i] = 0;
+ }
+}
+
+void earray_free(struct earray *array) {
+ int i;
+
+ mutex_lock(&array->mutex);
+
+ for (i = 0; i < array->ref_vect_len; i++) {
+ if (array->data[i] != 0) kfree(array->data[i]);
+ }
+ kfree(array->data);
+ array->data = 0;
+
+ //no need to unlock, the structure is never to be used again
+}
+
+int earray_add(struct earray *array, void *ptr) {
+ if (ptr == 0) return -1;
+
+ mutex_lock(&array->mutex);
+
+ int i, j;
+
+ for (i = 0; i < array->ref_vect_len; i++) {
+ if (array->data[i] == 0) {
+ // Allocate here
+ array->data[i] = kmalloc(array->vect_len * sizeof(void**));
+ array->data[i][0] = ptr;
+ for (j = 1; j < array->vect_len; j++) array->data[i][j] = 0;
+
+ j = i * array->vect_len; //ret val
+
+ if (array->elements <= j) array->elements = j + 1;
+
+ mutex_unlock(&array->mutex);
+ return j;
+ } else {
+ // Look for free space
+ for (j = 0; j < array->vect_len; j++) {
+ if (array->data[i][j] == 0) {
+ array->data[i][j] = ptr;
+
+ j = i * array->vect_len + j; // ret val
+ if (array->elements <= j) array->elements = j + 1;
+
+ mutex_unlock(&array->mutex);
+ return j;
+ }
+ }
+ }
+ }
+ // Nothing was allocated, we need MORE SPACE
+ void ***new_data = kmalloc(array->ref_vect_len + array->ref_vect_init_len);
+ for (i = 0; i < array->ref_vect_len; i++) {
+ new_data[i] = array->data[i];
+ }
+ new_data[array->ref_vect_len] = kmalloc(array->vect_len * sizeof(void**));
+ new_data[array->ref_vect_len][0] = ptr;
+ j = array->ref_vect_len * array->vect_len; // j = return value
+ for (i = 1; i < array->vect_len; i++) {
+ new_data[array->ref_vect_len][i] = 0;
+ }
+ for (i = array->ref_vect_len + 1; i < array->ref_vect_len + array->ref_vect_init_len; i++) {
+ new_data[i] = 0;
+ }
+ kfree(array->data);
+ array->data = new_data;
+ array->ref_vect_len += array->ref_vect_init_len;
+
+ ASSERT(j >= array->elements);
+ array->elements = j + 1;
+
+ mutex_unlock(&array->mutex);
+ return j;
+
+}
+
+void *earray_at(struct earray *array, int num) {
+ mutex_lock(&array->mutex);
+
+ int i = num / array->vect_len, j = num % array->vect_len;
+ if (i >= array->ref_vect_len || array->data[i] == 0) return 0;
+ void* ret = array->data[i][j];
+
+ mutex_unlock(&array->mutex);
+ return ret;
+}
+
+void earray_set(struct earray *array, int num, void* ptr) {
+ mutex_lock(&array->mutex);
+
+ int a = num / array->vect_len, b = num % array->vect_len, i, j;
+ if (a >= array->ref_vect_len) {
+ if (ptr == 0) {
+ mutex_unlock(&array->mutex);
+ return;
+ }
+ int new_vect_len = array->ref_vect_len;
+ while (a >= array->ref_vect_len) new_vect_len += array->ref_vect_init_len;
+
+ void ***new_data = kmalloc(new_vect_len * sizeof(void***));
+ for (i = 0; i < array->ref_vect_len; i++) {
+ new_data[i] = array->data[i];
+ }
+ for (i = array->ref_vect_len; i < new_vect_len; i++) {
+ new_data[i] = 0;
+ }
+ kfree(array->data);
+ array->data = new_data;
+ array->ref_vect_len = new_vect_len;
+ }
+ if (ptr == 0) {
+ if (array->data[a] != 0) {
+ if (array->data[a][b] != 0) {
+ array->data[a][b] = 0;
+ j = 1;
+ for (i = 0; i < array->vect_len; i++) {
+ if (array->data[a][i] != 0) j = 0;
+ }
+ if (j == 1) {
+ kfree(array->data[a]);
+ array->data[a] = 0;
+ }
+ }
+ }
+ } else {
+ if (array->data[a] = 0) {
+ array->data[a] = kmalloc(array->vect_len * sizeof(void**));
+ for (i = 0; i < array->vect_len; i++) array->data[a][i] = 0;
+ }
+ array->data[a][b] = ptr;
+
+ if (num >= array->elements) array->elements = num + 1;
+ }
+
+ mutex_unlock(&array->mutex);
+}
diff --git a/src/kernel/lib/earray.h b/src/kernel/lib/earray.h
new file mode 100644
index 0000000..69849c9
--- /dev/null
+++ b/src/kernel/lib/earray.h
@@ -0,0 +1,40 @@
+#ifndef DEF_EARRAY_H
+#define DEF_EARRAY_H
+
+#include <sched.h>
+
+/*
+ * This class implements a simple extensible array structure.
+ * An entry with a 0 value is considered free and can be allocated.
+ * The array will free as much space when elements are removed.
+ * The array will ALWAYS have array->data = 0 when uninitialized, !=0 when initialized and in use
+ * To initialize an earray:
+ * - allocate the struct earray
+ * - set its ref_vect_init_len and vect_len to desired values
+ * - set its data to 0
+ * - all the rest doesn't matter
+ * - call earray_init
+ * Freeing an array does not free the struct earray, only the data it references.
+ */
+
+struct earray {
+ int ref_vect_init_len;
+ int vect_len; // NEVER CHANGE THIS AFTER INITIALISATION!!!!
+
+ int ref_vect_len;
+ int elements;
+ void ***data;
+
+ mutex_t mutex;
+};
+
+void earray_init(struct earray *array);
+void earray_free(struct earray *earray); // frees everything
+
+int earray_add(struct earray *array, void* ptr); // return element number or -1 if fail
+void *earray_at(struct earray *array, int num); // returns 0 when nothing
+void earray_set(struct earray *earray, int num, void* ptr);
+
+
+#endif
+
diff --git a/src/kernel/lib/std.c b/src/kernel/lib/std.c
index 316dfa3..85dff1a 100644
--- a/src/kernel/lib/std.c
+++ b/src/kernel/lib/std.c
@@ -1,5 +1,6 @@
#include "std.h"
#include "core/sys.h"
+#include <mem/mem.h>
int errno = 0;
@@ -9,3 +10,10 @@ void abort() {
monitor_write("\n");
PANIC("abort() called, probably a memory manager failure.");
}
+
+char *strdup(const char *src) {
+ char* ret = kmalloc(strlen(src) + 1);
+ if (ret == NULL) return ret;
+ strcpy(ret, src);
+ return ret;
+}
diff --git a/src/kernel/lib/std.h b/src/kernel/lib/std.h
index 51e0435..7aaf1b9 100644
--- a/src/kernel/lib/std.h
+++ b/src/kernel/lib/std.h
@@ -11,4 +11,6 @@ void abort();
extern int errno;
+char *strdup(const char *src); // uses malloc, so needs to be here
+
#endif
diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c
index af6d057..fa8d179 100644
--- a/src/kernel/linker/elf.c
+++ b/src/kernel/linker/elf.c
@@ -27,7 +27,7 @@ thread_entry elf_load(uint8_t *data, struct process* process) {
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);
+ memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_filesz, 0, phdr[i].p_memsz - phdr[i].p_filesz);
}
if (phdr[i].p_vaddr + phdr[i].p_memsz > dataseg) {
dataseg = phdr[i].p_vaddr + phdr[i].p_memsz;
diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c
index 0527f06..8a1e2db 100644
--- a/src/kernel/mem/paging.c
+++ b/src/kernel/mem/paging.c
@@ -137,14 +137,13 @@ uint32_t paging_fault(struct registers *regs) {
}
if (seg == 0) {
- NL; WHERE; monitor_write("Unhandled Page Fault\t");
+ NL; WHERE; monitor_write("Unhandled Page Fault - ");
monitor_write("cr2:"); monitor_writeHex(addr);
- NL; TAB;
- if (regs->err_code & 0x1) monitor_write("present"); TAB;
- if (regs->err_code & 0x2) monitor_write("write"); TAB;
- if (regs->err_code & 0x4) monitor_write("user"); TAB;
- if (regs->err_code & 0x8) monitor_write("rsvd"); TAB;
- if (regs->err_code & 0x10) monitor_write("opfetch");
+ if (regs->err_code & 0x1) monitor_write(" present");
+ if (regs->err_code & 0x2) monitor_write(" write");
+ if (regs->err_code & 0x4) monitor_write(" user");
+ if (regs->err_code & 0x8) monitor_write(" rsvd");
+ if (regs->err_code & 0x10) monitor_write(" opfetch");
return 1;
}
return 0;
diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c
index aed5ea8..e6105d5 100644
--- a/src/kernel/task/idt.c
+++ b/src/kernel/task/idt.c
@@ -76,9 +76,9 @@ static struct irq_waiter {
void idt_isrHandler(struct registers regs) {
if ((regs.int_no == 14 && paging_fault(&regs) != 0) || regs.int_no != 14) {
if (tasking_handleException(&regs) == 0) {
- monitor_write("\nREALLY BAD THIS TIME\t\tUnhandled exception\t#");
+ monitor_write("\nREALLY BAD THIS TIME : Unhandled exception #");
monitor_writeDec(regs.int_no);
- monitor_write("\t@"); monitor_writeHex(regs.eip);
+ monitor_write(" @ eip:"); monitor_writeHex(regs.eip);
PANIC("Unhandled Exception");
}
}
@@ -105,14 +105,6 @@ void idt_irqHandler(struct registers regs) {
if (doSwitch) schedule();
}
-/* Called in idt_.asm on a system call (interrupt 64).
- Calls the correct syscall handler (if any). */
-void idt_syscallHandler(struct registers regs) {
- if (regs.eax < NUMBER_OF_SYSCALLS && syscalls[regs.eax] != 0) {
- syscalls[regs.eax](&regs);
- }
-}
-
/* For internal use only. Sets up an entry of the IDT with given parameters. */
static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
idt_entries[num].base_lo = base & 0xFFFF;
diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c
index bd27eba..8e1005c 100644
--- a/src/kernel/task/syscall.c
+++ b/src/kernel/task/syscall.c
@@ -2,18 +2,22 @@
#include "task.h"
#include <core/sys.h>
+#include <Object/Object.h>
+
+#define NUMBER_OF_SYSCALLS 32
+
#define CALL0(name, scname) static void scname(struct registers* r) { r->eax = name(); }
#define CALL1(name, scname) static void scname(struct registers* r) { \
- r->eax = name(r->ebx); }
+ r->eax = name(r->ecx); }
#define CALL2(name, scname) static void scname(struct registers* r) { \
- r->eax = name(r->ebx, r->ecx); }
+ r->eax = name(r->ecx, r->edx); }
#define CALL3(name, scname) static void scname(struct registers* r) { \
- r->eax = name(r->ebx, r->ecx, r->edx); }
+ r->eax = name(r->ecx, r->edx, r->esi); }
#define CALL0V(name, scname) static void scname(struct registers* r) { name(); }
-#define CALL1V(name, scname) static void scname(struct registers* r) { name(r->ebx); }
-#define CALL2V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx); }
-#define CALL3V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx, r->edx); }
-#define CALL4V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx, r->edx, r->esi); }
+#define CALL1V(name, scname) static void scname(struct registers* r) { name(r->ecx); }
+#define CALL2V(name, scname) static void scname(struct registers* r) { name(r->ecx, r->edx); }
+#define CALL3V(name, scname) static void scname(struct registers* r) { name(r->ecx, r->edx, r->esi); }
+#define CALL4V(name, scname) static void scname(struct registers* r) { name(r->ecx, r->edx, r->esi, r->edi); }
CALL0V(thread_exit, thread_exit_sc);
CALL0V(schedule, schedule_sc);
@@ -25,21 +29,61 @@ CALL0(proc_priv, proc_priv_sc);
CALL1(process_sbrk, proc_sbrk_sc);
CALL1V(process_brk, proc_brk_sc);
+CALL1(open, open_sc);
+CALL2(open_relative, open_relative_sc);
+CALL1V(close, close_sc);
+CALL2(get_methods, get_methods_sc);
+
static void thread_new_sc(struct registers* r) {
cli();
- thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx);
+ thread_new(current_thread->process, (thread_entry)r->ecx, (void*)r->edx, (void*)r->esi);
sti();
}
int_callback syscalls[NUMBER_OF_SYSCALLS] = {
- thread_exit_sc, //0
+ 0, //0
+ thread_exit_sc,
schedule_sc,
thread_sleep_sc,
process_exit_sc,
- printk_sc,
- thread_new_sc, //5
+ printk_sc, //5
+ thread_new_sc,
irq_wait_sc,
proc_priv_sc,
proc_sbrk_sc,
- proc_brk_sc,
- 0 };
+ proc_brk_sc, //10
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, //15
+ 0,
+ 0,
+ 0,
+ 0,
+ open_sc, //20
+ open_relative_sc,
+ close_sc,
+ get_methods_sc,
+ 0,
+ 0, //25
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, //30
+ 0, //31
+
+ };
+
+/* Called in idt_.asm on a system call (interrupt 64).
+ Calls the correct syscall handler (if any). */
+void idt_syscallHandler(struct registers regs) {
+ if (regs.eax == 0) {
+ if (regs.ebx < NUMBER_OF_SYSCALLS && syscalls[regs.ebx] != 0) {
+ syscalls[regs.ebx](&regs);
+ }
+ } else {
+ do_method_call(&regs);
+ }
+}
diff --git a/src/kernel/task/syscall.h b/src/kernel/task/syscall.h
index f03be55..54af108 100644
--- a/src/kernel/task/syscall.h
+++ b/src/kernel/task/syscall.h
@@ -3,8 +3,6 @@
#include "idt.h"
-#define NUMBER_OF_SYSCALLS 32
-
extern int_callback syscalls[];
#endif
diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c
index 9d98165..4c99bf7 100644
--- a/src/kernel/task/task.c
+++ b/src/kernel/task/task.c
@@ -7,6 +7,8 @@
#include <mem/gdt.h>
#include "timer.h"
+#include <Object/Object.h>
+
#define KSTACKSIZE 0x8000
//Static routines for handling threads exiting and all cleanup
@@ -286,6 +288,13 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi
p->data = 0;
p->dataseg = 0;
+ p->handles.ref_vect_init_len = 32;
+ p->handles.vect_len = 128;
+ p->handles.data = 0;
+ earray_init(&p->handles);
+ ASSERT(earray_add(&p->handles, 0xFFFFFFF0) == 0);
+ ASSERT(earray_add(&p->handles, 0xFFFFFFF0) == 1);
+
p->stack = 0;
if (p->privilege >= PL_USER) { //We are running in user mode
size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000;
@@ -319,6 +328,8 @@ static void thread_delete(struct thread *th) {
/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */
static void process_delete(struct process *pr) {
+ int i;
+
struct thread *it = pr->threads;
while (it != 0) {
thread_delete(it);
@@ -336,31 +347,19 @@ static void process_delete(struct process *pr) {
it = it->next;
}
}
+ for (i = 1; i < pr->handles.elements; i++) {
+ Object* obj = earray_at(&pr->handles, i);
+ if (obj != 0) {
+ obj->handles--;
+ if (obj->_class->closed != 0) obj->_class->closed(obj);
+ }
+ }
+ earray_free(&pr->handles);
+
pagedir_delete(pr->pagedir);
kfree(pr);
}
-/* System call. Called by the app to define the place for the heap. */
-/*int process_setheapseg(size_t start, size_t end) { //syscall
- struct process *p = current_thread->process;
- if (start >= K_HIGHHALF_ADDR || end >= K_HIGHHALF_ADDR) return -1;
- if (p->heapseg == 0) {
- struct segment *s = simpleseg_make(start, end - start, 1);
- if (s == 0) return -5;
- p->heapseg = seg_map(s, p->pagedir, 0);
- if (p->heapseg == 0) return -1;
- return 0;
- } else if (p->heapseg->start != start) {
- seg_unmap(p->heapseg);
- struct segment *s = simpleseg_make(start, end - start, 1);
- if (s == 0) return -5;
- p->heapseg = seg_map(s, p->pagedir, 0);
- if (p->heapseg == 0) return -1;
- return 0;
- } else {
- return simpleseg_resize(p->heapseg, end - start);
- }
-}*/
size_t process_sbrk(size_t size) {
struct process *p = current_thread->process;
diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h
index 63cb35a..dbeb638 100644
--- a/src/kernel/task/task.h
+++ b/src/kernel/task/task.h
@@ -3,6 +3,7 @@
#include <types.h>
#include <mem/paging.h>
+#include <lib/earray.h>
#include "idt.h"
#define TS_RUNNING 0
@@ -28,6 +29,8 @@ struct process {
struct segment_map *dataseg;
+ struct earray handles;
+
struct process *next; //Forms a linked list
struct thread *threads;
};
@@ -44,6 +47,7 @@ struct thread {
};
extern struct thread *current_thread;
+#define current_process (current_thread != 0 ? current_thread->process : 0)
void tasking_init();
void schedule();
diff --git a/src/user/lib/Makefile b/src/user/lib/Makefile
index 4019e88..4b88336 100644
--- a/src/user/lib/Makefile
+++ b/src/user/lib/Makefile
@@ -1,5 +1,6 @@
Out = _user.o
-Obj = tce/syscall.o std/_dlmalloc.o \
+Obj = tce/syscall.o tce/Folder.o \
+ std/_dlmalloc.o \
std/stdio.o std/stdlib.o \
start.o
ExtObj = $(SrcPath)/common/_common.o
diff --git a/src/user/lib/include/stdio.h b/src/user/lib/include/stdio.h
index e3f9d89..3b6c2d2 100644
--- a/src/user/lib/include/stdio.h
+++ b/src/user/lib/include/stdio.h
@@ -1,6 +1,8 @@
#ifndef DEF_STDIO_H
#define DEF_STDIO_H
+#include <tce/syscall.h>
+
void printk_int(int number);
void printk_hex(unsigned number);
diff --git a/src/user/lib/include/tce/Folder.h b/src/user/lib/include/tce/Folder.h
new file mode 100644
index 0000000..3a796d9
--- /dev/null
+++ b/src/user/lib/include/tce/Folder.h
@@ -0,0 +1,12 @@
+#ifndef DEF_LIB_TCE_USER_FOLDER_H
+#define DEF_LIB_TCE_USER_FOLDER_H
+
+#include <tce/Folder_common.h>
+#include <tce/Object.h>
+
+struct FolderMethods *Folder_getMethods();
+
+int Folder_GetChildNameAt(Object object, int pos, char* to);
+
+#endif
+
diff --git a/src/user/lib/include/tce/Object.h b/src/user/lib/include/tce/Object.h
new file mode 100644
index 0000000..f363bd6
--- /dev/null
+++ b/src/user/lib/include/tce/Object.h
@@ -0,0 +1,17 @@
+#ifndef DEF_TCE_OBJ_USER_LIB_H
+#define DEF_TCE_OBJ_USER_LIB_H
+
+#include <tce/syscall.h>
+#include <tce/Object_common.h>
+
+typedef int Object;
+
+Object open(char* name);
+Object open_relative(char* name, Object parent);
+void close(Object object);
+int get_methods(char* iface, int* whereto);
+
+int Call(int method, Object object, size_t a, size_t b, size_t c, size_t d);
+
+#endif
+
diff --git a/src/user/lib/std/stdio.c b/src/user/lib/std/stdio.c
index 63ad357..c11dd05 100644
--- a/src/user/lib/std/stdio.c
+++ b/src/user/lib/std/stdio.c
@@ -32,7 +32,6 @@ void printk_int(int number) {
}
r[order] = 0;
printk(s);
- free(s);
}
void printk_hex(unsigned v) {
diff --git a/src/user/lib/tce/Folder.c b/src/user/lib/tce/Folder.c
new file mode 100644
index 0000000..9b0a773
--- /dev/null
+++ b/src/user/lib/tce/Folder.c
@@ -0,0 +1,24 @@
+#include <tce/Folder.h>
+#include <stdio.h>
+
+static struct FolderMethods _folderMethods = { 0 };
+
+struct FolderMethods *Folder_getMethods() {
+ int i;
+ if (_folderMethods.GetChildNameAt == -1) return 0;
+ if (_folderMethods.GetChildNameAt == 0) {
+ i = get_methods("Folder", (int*)&_folderMethods);
+ if (i < 0) {
+ _folderMethods.GetChildNameAt = -1;
+ return 0;
+ }
+ }
+ return &_folderMethods;
+}
+
+int Folder_GetChildNameAt(Object object, int pos, char *to) {
+ struct FolderMethods *folder = Folder_getMethods();
+ if (folder == 0) return E_NOT_IMPLEMENTED;
+
+ return Call(folder->GetChildNameAt, object, pos, to, 0, 0);
+}
diff --git a/src/user/lib/tce/syscall.c b/src/user/lib/tce/syscall.c
index f9243b0..b779bb6 100644
--- a/src/user/lib/tce/syscall.c
+++ b/src/user/lib/tce/syscall.c
@@ -1,4 +1,5 @@
#include <tce/syscall.h>
+#include <tce/Object.h>
#include <stdlib.h>
#include <sched.h>
@@ -8,24 +9,26 @@ static size_t call(size_t a, size_t b, size_t c, size_t d, size_t e, size_t f) {
return ret;
}
+// Standard syscalls
+
void thread_exit() {
- call(0, 0, 0, 0, 0, 0);
+ call(0, 1, 0, 0, 0, 0);
}
void schedule() {
- call(1, 0, 0,0, 0, 0);
+ call(0, 2, 0,0, 0, 0);
}
void thread_sleep(int time) {
- call(2, time, 0, 0, 0, 0);
+ call(0, 3, time, 0, 0, 0);
}
void process_exit(int retval) {
- call(3, retval, 0, 0, 0, 0);
+ call(0, 4, retval, 0, 0, 0);
}
void printk(char* str) {
- call(4, (unsigned)str, 0, 0, 0, 0);
+ call(0, 5, (unsigned)str, 0, 0, 0);
}
//THREAD CREATION
@@ -44,28 +47,51 @@ void thread_start(void *data) {
if (_stack_to_free != 0) free(_stack_to_free);
_stack_to_free = tsd->stack;
asm volatile("movl %0, (_stack_freeing_mutex); int $64;" ::
- "a"(0), "r"(MUTEX_UNLOCKED));
+ "a"(0), "b"(1), "r"(MUTEX_UNLOCKED));
}
+
void thread_new(void (*entry)(void*), void *data) {
struct thread_start_data *tsd = malloc(sizeof(struct thread_start_data));
tsd->entry = entry;
tsd->data = data;
tsd->stack = malloc(NEW_STACK_SIZE);
- call(5, (unsigned)thread_start, (unsigned)tsd, (unsigned)(tsd->stack + NEW_STACK_SIZE), 0, 0);
+ call(0, 6, (unsigned)thread_start, (unsigned)tsd, (unsigned)(tsd->stack + NEW_STACK_SIZE), 0);
}
void irq_wait(int number) {
- call(6, number, 0, 0, 0, 0);
+ call(0, 7, number, 0, 0, 0);
}
int proc_priv() {
- return call(7, 0, 0, 0, 0, 0);
+ return call(0, 8, 0, 0, 0, 0);
}
void* sbrk(size_t s) {
- return (void*)call(8, s, 0, 0, 0, 0);
+ return (void*)call(0, 9, s, 0, 0, 0);
}
void brk(void* ptr) {
- return call (9, ptr, 0, 0, 0, 0);
+ return call (0, 10, ptr, 0, 0, 0);
+}
+
+// Has to do with objects
+
+Object open(char* name) {
+ return call(0, 20, name, 0, 0, 0);
+}
+
+Object open_relative(char* name, Object parent) {
+ return call(0, 21, name, parent, 0, 0);
+}
+
+void close(Object o) {
+ call(0, 22, o, 0, 0, 0);
+}
+
+int get_methods(char *iface, int* whereto) {
+ call(0, 23, iface, whereto, 0, 0);
+}
+
+int Call(int method, Object object, size_t a, size_t b, size_t c, size_t d) {
+ return call(object, method, a, b, c, d);
}
diff --git a/src/user/test/main.c b/src/user/test/main.c
index 945c530..f8fec48 100644
--- a/src/user/test/main.c
+++ b/src/user/test/main.c
@@ -1,9 +1,15 @@
#include <tce/syscall.h>
#include <stdlib.h>
+#include <tce/Folder.h>
+#include <stdio.h>
+
+int threads = 0;
void thread_cascade(void* d) {
int n = (int)d;
+ threads++;
+
if (d == 0) {
//printk("{#} 0 cascade element started => end\n");
printk("*");
@@ -25,16 +31,71 @@ void thread_cascade(void* d) {
//printk("{#} Thread cascade element finished.\n");
printk(".");
}
+
+ threads--;
+}
+
+void read_dir(Object o, int l) {
+ int i = 0, j;
+ char name[FILENAME_MAX_LEN];
+ while (1) {
+ for (j = 0; j < l; j++) printk(" ");
+ j = Folder_GetChildNameAt(o, i, name);
+ if (j <= 0) {
+ printk(" - reached end : ");
+ printk_int(j);
+ printk("\n");
+ break;
+ }
+ printk(" - '");
+ printk(name);
+
+ if (strcmp(name, ".") == 0) {
+ printk("', skipping -_-'\n");
+ } else {
+ Object oo = open_relative(name, o);
+ if (oo <= 0) {
+ printk("', failed to open, error ");
+ printk_int(oo);
+ printk("...\n");
+ } else {
+ printk("', opened as ");
+ printk_int(oo);
+ printk(", content:\n");
+ read_dir(oo, l+1);
+ }
+ }
+ i++;
+ }
}
+
int main() {
- printk("Hi world from test module !\n");
+ printk("Test starts. ");
- printk(" -> Creating thread cascade (total 2**8 = 256 threads)\n");
- thread_new(thread_cascade, (void*)8);
+ printk("Create thread cascade (2**5 = 32 threads). ");
+ thread_new(thread_cascade, (void*)5);
- printk(" -> Main thread now sleeping... forever...\n");
+ printk("Main thread waits.\n");
while (1) {
+ thread_sleep(100);
+ if (threads == 0) break;
+ }
+ printk("\nOk, that was fine. Now trying something else...\n");
+ Object o = open("/");
+ if (o <= 0) {
+ printk("Cannot open '/', error ");
+ printk_int(o);
+ printk("...\n");
+ } else {
+ printk("Reading '/' (");
+ printk_int(o);
+ printk(") :\n");
+ read_dir(o, 0);
+ }
+
+ printk("Ok. Now sleeping, forever and ever.");
+ while(1) {
thread_sleep(1000);
}
return 0;