diff options
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(¤t_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(¤t_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(¤t_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(®s) != 0) || regs.int_no != 14) { if (tasking_handleException(®s) == 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](®s); - } -} - /* 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](®s); + } + } else { + do_method_call(®s); + } +} 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; |