From ad1ec29070e1ffba7461687cd268e64be06aa78b Mon Sep 17 00:00:00 2001 From: Alexis211 Date: Tue, 30 Mar 2010 19:22:23 +0200 Subject: More work on IPC and userland tools. --- doc/memlayout.txt | 8 ++ doc/method.txt | 1 + doc/roadmap.txt | 12 +++ doc/syscalls.txt | 4 +- src/include/gc/mem.h | 9 ++ src/include/gc/obj.h | 14 +++ src/include/gc/server.h | 79 ++++++++++++++ src/include/gc/syscall.h | 4 +- src/include/gm/method.h | 22 ++++ src/kernel/ipc/request.c | 36 ++++--- src/kernel/ipc/request.h | 4 +- src/kernel/linker/elf.c | 6 ++ src/kernel/mem/paging.c | 1 - src/kernel/mem/paging.h | 2 +- src/kernel/mem/seg.c | 21 ++++ src/kernel/mem/seg.h | 1 + src/kernel/task/idt.h | 1 - src/kernel/task/idt_.asm | 6 -- src/kernel/task/syscall.c | 2 + src/kernel/task/task.c | 24 +++++ src/kernel/task/task.h | 3 + src/library/Makefile | 2 + src/library/gc/mem.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++ src/library/gc/object.c | 178 +++++++++++++++++++++++++++++++ src/library/gc/syscall.c | 8 +- src/library/link.ld | 2 +- src/library/start.c | 1 + src/modules/test/main.c | 41 ++++++-- 28 files changed, 716 insertions(+), 38 deletions(-) create mode 100644 doc/memlayout.txt create mode 100644 doc/method.txt create mode 100644 doc/roadmap.txt create mode 100644 src/include/gc/mem.h create mode 100644 src/include/gc/obj.h create mode 100644 src/include/gc/server.h create mode 100644 src/include/gm/method.h create mode 100644 src/library/gc/mem.c create mode 100644 src/library/gc/object.c diff --git a/doc/memlayout.txt b/doc/memlayout.txt new file mode 100644 index 0000000..6720d00 --- /dev/null +++ b/doc/memlayout.txt @@ -0,0 +1,8 @@ +This is the memory layout of a standard service : + +- 0x00100000 to 0x20000000 Application's code and static data +- 0x20000000 to 0x6F000000 Application's heap +- 0x70000000 to 0x80000000 Free space, can be used for mapping device memory +- 0x80000000 to 0xD0000000 Space for mapping shared memory segments +- 0xD0000000 to 0xDF000000 Stacks (automatically allocated by kernel, size 0x8000 each) +- 0xE0000000 to 0xFFFFFFFF Kernel code and heap diff --git a/doc/method.txt b/doc/method.txt new file mode 100644 index 0000000..066e0ae --- /dev/null +++ b/doc/method.txt @@ -0,0 +1 @@ +All methods are defined in src/include/gm/method.h and src/include/gm/m/* diff --git a/doc/roadmap.txt b/doc/roadmap.txt new file mode 100644 index 0000000..7304e4b --- /dev/null +++ b/doc/roadmap.txt @@ -0,0 +1,12 @@ +** 0.0.4 'Cat in my heart' ** +- [OK] Userland heap (meaning kernel can give memory to processes) +- Userland helper functions for objects (server and client) +- Basic object method for knowing if object handles another method (list methods in src/include/gm) +- Userland library for writing numbers and other stuff +- A manager module that manages all other running modules (the privilege of manager is given by the kernel to the first module loaded) + +** 0.0.5 'Truth is better cold' ** +- Review privilege system +- Driver processes can ask to map physical memory in their address space +- Describe interfaces for server (any service's main object), reader and writer. +- Keyboard driver, userland display driver, virtual terminal driver diff --git a/doc/syscalls.txt b/doc/syscalls.txt index 6846fb9..67b4b3c 100644 --- a/doc/syscalls.txt +++ b/doc/syscalls.txt @@ -31,6 +31,8 @@ id=eax Name Parameters Description 17 request ebx: object descriptor Send a blocking request to object ecx: pointer to user_sendrequest struct with information 18 send_msg same as above Send a nonblocking request to object, same as above + 19 proc_setheap ebx: start address Creates/resizes/moves the heap segment allocated to this process (one per process) + ecx: end address If a processes wishes to exit with an error code, it HAS to use process_exit. thread_exit will do nothing. @@ -73,7 +75,7 @@ Returns: - 2 if a request is being processed = request_answer (15) -Parameters: an object descriptor, two ints forming a long long if necessary +Parameters: an object descriptor, two ints forming a long long if necessary, an int which is the return status (error code) of the function Returns: nothing Answers a request marked as currently being processed, ignoring cases where : - descriptor does not exist diff --git a/src/include/gc/mem.h b/src/include/gc/mem.h new file mode 100644 index 0000000..2557289 --- /dev/null +++ b/src/include/gc/mem.h @@ -0,0 +1,9 @@ +#ifndef DEF_HEAP_H +#define DEF_HEAP_H + +#include "gc/syscall.h" + +void* malloc(size_t size); +void free(void* p); + +#endif diff --git a/src/include/gc/obj.h b/src/include/gc/obj.h new file mode 100644 index 0000000..10651f5 --- /dev/null +++ b/src/include/gc/obj.h @@ -0,0 +1,14 @@ +#ifndef DEF_OBJ_H +#define DEF_OBJ_H + +// generic method error codes +#define ME_UNHANDLED -32767 +#define ME_INTERRUPTED -32766 + +struct object_cli { + int id; +}; + +typedef struct object_cli Object; + +#endif diff --git a/src/include/gc/server.h b/src/include/gc/server.h new file mode 100644 index 0000000..b98b4fb --- /dev/null +++ b/src/include/gc/server.h @@ -0,0 +1,79 @@ +#ifndef DEF_SERVER_H +#define DEF_SERVER_H + +#include "syscall.h" +#include "obj.h" + +//parameter/return values types +#define PT_VOID 0 +#define PT_OBJDESC 1 +#define PT_LONG 2 +#define PT_LONGLONG 3 //for return values +#define PT_SHM 3 + +struct method_data { + struct { + union { + int i; + void* p; + } val; + int type; + int keepShm; //for messages : keep shared memory segment after return or unmap ? (default : 0 = unmap) + } parameters[3]; + uint32_t func; + int blocking; //1 : blocking request, 0 : message + struct object_srv *obj; +}; + +struct method_ret { + union { + int i; + int64_t l; + }; + int type; + int status; //= error code if any +}; + +//helper function for creating return values +struct method_ret mr_long(int val); +struct method_ret mr_llong(int64_t val); +struct method_ret mr_obj(Object* obj); +struct method_ret mr_srv(struct object_srv* obj); +struct method_ret mr_void(); +struct method_ret mr_err(int error); + +typedef struct method_ret (*method_handler)(struct method_data*); + +struct method_srv { + uint32_t id; + method_handler h; + + struct method_srv *next; +}; + +struct object_srv { + int id; //descriptor + struct method_srv *methods; + + void *data; + + struct object_srv *next; +}; + +typedef struct object_srv Server; + +extern Server procServer; //corresponds to descriptor 0. + +//possible actions for srv_handle +#define HA_ONCE 1 //check if requests are waiting, if so handle them +#define HA_WAIT 2 //check if requests are waiting, if so handle them, else wait for one to come and handle it +#define HA_LOOP 3 //wait for requests to come, handling them in an infinite loop + +void srv_handleAll(); //check all objects once +void srv_handle(Server* o, int act); + +Server *srv_create(); +void srv_delete(Server *o); +void srv_addHandler(Server* o, uint32_t method, method_handler h); + +#endif diff --git a/src/include/gc/syscall.h b/src/include/gc/syscall.h index 5287d85..f731e10 100644 --- a/src/include/gc/syscall.h +++ b/src/include/gc/syscall.h @@ -21,6 +21,7 @@ struct user_sendrequest { uint32_t func, a, b, c; uint32_t answeri; int64_t answerll; + int errcode; }; void thread_exit(); @@ -38,9 +39,10 @@ int object_owned(int descriptor); void object_close(int descriptor); int request_get(int descriptor, struct user_request *rq, int wait); int request_has(int descriptor); -void request_answer(int descriptor, int answer1, int answer2); +void request_answer(int descriptor, uint32_t answer1, uint32_t answer2, int errcode); int request_mapShm(int descriptor, size_t offset, int number); int request(int descriptor, struct user_sendrequest *rq); int send_msg(int descriptor, struct user_sendrequest *rq); +int proc_setheap(size_t start, size_t end); #endif diff --git a/src/include/gm/method.h b/src/include/gm/method.h new file mode 100644 index 0000000..ac6ab0e --- /dev/null +++ b/src/include/gm/method.h @@ -0,0 +1,22 @@ +#ifndef DEF_METHOD_H +#define DEF_METHOD_H + +#define MP(r, a, b, c) (((r << 6) | (a << 4) | (b << 2) | c) << 24) + +/* ****** FORMAT FOR #define NAMES : ****** + * M__ + * where ret, param1, param2 and param3 are one of the following : + * - V (0) : nothing (void) + * - O (1) : object descriptor + * - I (2) : int + * - B (2) : int used as a boolean (0 = no, 1 = yes) + * - M (3) : shared memory, only for parameters + * - L (3) : int64 (long long), only for return values + */ + +#define M_HANDLECHECK_BIVV (1 | MP(2, 2, 0, 0)) +#define M_HANDLECHECK_BMIV (1 | MP(2, 3, 2, 0)) +/* Checks if object handles that method. In case BIVV, only one method is checked for. + * In case BMIV, the [b] methods in shared memory [a] are checked, first one not found returns false. */ + +#endif diff --git a/src/kernel/ipc/request.c b/src/kernel/ipc/request.c index 9e42d6a..e59a66c 100644 --- a/src/kernel/ipc/request.c +++ b/src/kernel/ipc/request.c @@ -47,7 +47,7 @@ int request_has(int id) { return 2; } -void request_answer(int id, uint32_t answer, uint32_t answer2) { +void request_answer(int id, uint32_t answer, uint32_t answer2, int errcode) { int i; //check if we own the object, if not return (also return if descriptor does not exist) struct object *obj = objdesc_read(current_thread->process, id); @@ -64,22 +64,27 @@ void request_answer(int id, uint32_t answer, uint32_t answer2) { obj->request->acknowledged = RS_FINISHED; switch (obj->request->func >> 30) { case PT_OBJDESC: - if (obj->owner == obj->request->requester->process) { + if ((int)answer <= 0) { obj->request->answer.n = answer; } else { - int n = objdesc_get(obj->request->requester->process, objdesc_read(obj->owner, answer)); - if (n == -1) { - n = objdesc_add(obj->request->requester->process, objdesc_read(obj->owner, answer)); + if (obj->owner == obj->request->requester->process) { + obj->request->answer.n = answer; + } else { + int n = objdesc_get(obj->request->requester->process, objdesc_read(obj->owner, answer)); + if (n == -1) { + n = objdesc_add(obj->request->requester->process, objdesc_read(obj->owner, answer)); + } + obj->request->answer.n = n; } - obj->request->answer.n = n; } break; case PT_LONG: obj->request->answer.n = answer; break; case PT_LONGLONG: - obj->request->answer.ll = (uint64_t)((uint64_t)answer << 32) | answer2; + obj->request->answer.ll = (uint64_t)((uint64_t)answer2 << 32) | answer; } + obj->request->errcode = errcode; //wake up receiver thread (thread_wakeUp) thread_wakeUp(obj->request->requester); //dereference request from object, unlock objects busymutex @@ -150,15 +155,19 @@ static struct request *mkrequest(int id, struct thread *requester, uint32_t v = (i == 0 ? a : (i == 1 ? b : c)); switch (n) { case PT_OBJDESC: - if (obj->owner == current_thread->process) { + if ((int)v <= 0) { rq->params[i] = v; } else { - int d = objdesc_get(obj->owner, objdesc_read(current_thread->process, v)); - if (d == -1) { - d = objdesc_add(obj->owner, objdesc_read(current_thread->process, v)); - rq->obj_close[i] = d; + if (obj->owner == current_thread->process) { + rq->params[i] = v; + } else { + int d = objdesc_get(obj->owner, objdesc_read(current_thread->process, v)); + if (d == -1) { + d = objdesc_add(obj->owner, objdesc_read(current_thread->process, v)); + rq->obj_close[i] = d; + } + rq->params[i] = d; } - rq->params[i] = d; } break; case PT_LONG: @@ -201,6 +210,7 @@ int request(int obj, uint32_t rq_ptr) { case PT_LONGLONG: urq->answerll = rq->answer.ll; } + urq->errcode = rq->errcode; kfree(rq); return 0; } diff --git a/src/kernel/ipc/request.h b/src/kernel/ipc/request.h index 0b60a5c..0afc48b 100644 --- a/src/kernel/ipc/request.h +++ b/src/kernel/ipc/request.h @@ -24,6 +24,7 @@ struct request { int64_t ll; uint32_t n; } answer; + int errcode; //returned when function has finished }; struct user_request { @@ -35,12 +36,13 @@ struct user_sendrequest { uint32_t func, a, b, c; uint32_t answeri; int64_t answerll; + int errcode; }; //syscalls int request_get(int obj, uint32_t ptr, int wait); int request_has(int obj); -void request_answer(int obj, uint32_t answer, uint32_t answer2); //answer2 used for long long. +void request_answer(int obj, uint32_t answer, uint32_t answer2, int errcode); //answer2 used for long long. int request_mapShm(int obj, uint32_t pos, int number); int request(int obj, uint32_t rq_ptr); diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c index bbf4906..6ad5d34 100644 --- a/src/kernel/linker/elf.c +++ b/src/kernel/linker/elf.c @@ -16,6 +16,8 @@ thread_entry elf_load(uint8_t *data, struct process* process) { int i; if (elf_check(data)) return 0; + struct page_directory *r = current_pagedir; + cli(); pagedir_switch(process->pagedir); phdr = (struct elf_phdr*)((uint8_t*)(data + ehdr->e_phoff)); @@ -28,6 +30,10 @@ thread_entry elf_load(uint8_t *data, struct process* process) { } } } + + pagedir_switch(r); + sti(); + return (thread_entry)ehdr->e_entry; } diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c index 8996162..9972b2a 100644 --- a/src/kernel/mem/paging.c +++ b/src/kernel/mem/paging.c @@ -22,7 +22,6 @@ void frame_free(uint32_t id) { bitset_clear(&frames, id); } - void paging_init(size_t totalRam) { uint32_t i; diff --git a/src/kernel/mem/paging.h b/src/kernel/mem/paging.h index cb76cd6..ec10560 100644 --- a/src/kernel/mem/paging.h +++ b/src/kernel/mem/paging.h @@ -26,7 +26,7 @@ struct page_directory { struct segment_map *mappedSegs; }; -extern struct page_directory *kernel_pagedir; +extern struct page_directory *kernel_pagedir, *current_pagedir; uint32_t frame_alloc(); void frame_free(uint32_t id); diff --git a/src/kernel/mem/seg.c b/src/kernel/mem/seg.c index aa71564..ffaa84c 100644 --- a/src/kernel/mem/seg.c +++ b/src/kernel/mem/seg.c @@ -71,3 +71,24 @@ int simpleseg_handleFault(struct segment_map* sm, size_t addr, int write) { void simpleseg_delete(struct segment* seg) { } + +int simpleseg_resize(struct segment_map *map, size_t len) { + size_t i; + + if (map == 0) return -1; + if (map->seg->delete != simpleseg_delete) return -2; + + struct simpleseg *s = (struct simpleseg*)map->seg->seg_data; + if (len & 0xFFF) len = (len & 0xFFFFF000) + 0x1000; + if (len < map->len) { + for (i = map->start + len; i < map->start + map->len; i += 0x1000) { + page_unmapFree(pagedir_getPage(map->pagedir, i, 0)); + } + map->len = len; + s->len = len; + } else if (len > map->len) { + map->len = len; + s->len = len; + } + return 0; +} diff --git a/src/kernel/mem/seg.h b/src/kernel/mem/seg.h index 4d6660f..26664dc 100644 --- a/src/kernel/mem/seg.h +++ b/src/kernel/mem/seg.h @@ -37,5 +37,6 @@ struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pa void simpleseg_unmap(struct segment_map*); void simpleseg_delete(struct segment *seg); int simpleseg_handleFault(struct segment_map* map, size_t addr, int write); +int simpleseg_resize(struct segment_map *map, size_t len); #endif diff --git a/src/kernel/task/idt.h b/src/kernel/task/idt.h index ed37eb0..b12d6c5 100644 --- a/src/kernel/task/idt.h +++ b/src/kernel/task/idt.h @@ -17,7 +17,6 @@ struct idt_ptr { } __attribute__((packed)); struct registers { - uint32_t cr3; //page directory physical address uint32_t ds; // Data segment selector uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha. uint32_t int_no, err_code; // Interrupt number and error code (if applicable) diff --git a/src/kernel/task/idt_.asm b/src/kernel/task/idt_.asm index 1a594ca..95878c0 100644 --- a/src/kernel/task/idt_.asm +++ b/src/kernel/task/idt_.asm @@ -47,14 +47,8 @@ idt_flush: mov fs, ax mov gs, ax - mov eax, cr3 - push eax - call idt_%1Handler - pop eax - mov cr3, eax - pop eax ; reload the original data segment descriptor mov ds, ax mov es, ax diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c index dd909e0..9a1ce81 100644 --- a/src/kernel/task/syscall.c +++ b/src/kernel/task/syscall.c @@ -31,6 +31,7 @@ CALL3V(request_answer, request_answer_sc); CALL3(request_mapShm, request_mapShm_sc); CALL2(request, request_sc); CALL2(send_msg, send_msg_sc); +CALL2(process_setheapseg, proc_setheap_sc); static void thread_new_sc(struct registers* r) { thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx); @@ -56,4 +57,5 @@ int_callback syscalls[] = { request_mapShm_sc, request_sc, send_msg_sc, + proc_setheap_sc, 0 }; diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c index dec7565..9221813 100644 --- a/src/kernel/task/task.c +++ b/src/kernel/task/task.c @@ -77,6 +77,7 @@ void tasking_switch() { } current_thread = thread_next(); + pagedir_switch(current_thread->process->pagedir); gdt_setKernelStack(((uint32_t)current_thread->kernelStack_addr) + current_thread->kernelStack_size); @@ -278,6 +279,7 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi p->pagedir = pagedir_new(); p->next = processes; p->stacksBottom = 0xDF000000; + p->heapseg = 0; p->next_objdesc = 0; p->objects = 0; @@ -289,6 +291,7 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi static void thread_delete(struct thread *th) { kfree(th->kernelStack_addr); + if (th->userStack_seg != 0) seg_unmap(th->userStack_seg); th->process->threads--; if (threads == th) { threads = th->next; @@ -319,3 +322,24 @@ static void process_delete(struct process *pr) { } kfree(pr); } + +int process_setheapseg(size_t start, size_t end) { //syscall + struct process *p = current_thread->process; + if (start >= 0xE0000000 || end >= 0xE0000000) 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); + } +} diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 1c22785..3dad63d 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -32,6 +32,8 @@ struct process { struct obj_descriptor *objects; uint32_t next_objdesc; + struct segment_map *heapseg; + struct process *next; //Forms a linked list }; @@ -62,5 +64,6 @@ void thread_exit(); void process_exit(uint32_t retval); struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data); struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege); +int process_setheapseg(size_t start, size_t end); //syscall #endif diff --git a/src/library/Makefile b/src/library/Makefile index 74eb525..be5a76d 100644 --- a/src/library/Makefile +++ b/src/library/Makefile @@ -8,6 +8,8 @@ LDFLAGS = -r Library = grapes.o Objects = gc/syscall.o \ + gc/mem.o \ + gc/object.o \ start.o all: $(Library) diff --git a/src/library/gc/mem.c b/src/library/gc/mem.c new file mode 100644 index 0000000..fe243ba --- /dev/null +++ b/src/library/gc/mem.c @@ -0,0 +1,262 @@ +#include "gc/mem.h" + +struct heap_header { + uint32_t magic; + uint32_t is_hole; + size_t size; +}; + +struct heap_footer { + uint32_t magic; + struct heap_header *header; +}; + +struct heap { + struct heap_header **idx; + uint32_t idxused; + size_t start_addr, end_addr, max_end; +}; + +int heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize); +void* heap_alloc(struct heap *heap, size_t sz); +void heap_free(struct heap *heap, void* ptr); + +#define HEAP_MAGIC 0xBAD0BEEF +#define HEAP_MIN_SIZE 0x4000 + +/* ******************* GENERAL MEMORY FUNCTIONS ******************** */ + +static struct heap h; +static int heap_ok = 0; + +void* malloc(size_t size) { + if (heap_ok == 0) { + if (heap_create(&h, 0x20000000, 0x00010000, 0x00100000, 0x4F000000)) return 0; + heap_ok = 1; + } + return heap_alloc(&h, size); +} + +void free(void* p) { + if (heap_ok == 0 || (size_t)p < h.start_addr || (size_t)p > h.end_addr) return; + heap_free(&h, p); +} + +static int setheapseg (struct heap *heap, size_t start, size_t end, size_t prev_end) { //returns nonzero on error + if (heap == &h) { + return proc_setheap(start, end); + } //otherwise, something else might be done. + return -1; +} + +/* ******************* HEAP HEADER ****************** */ + +static void heapIdx_insert(struct heap *heap, struct heap_header *e) { + if ((heap->idxused + sizeof(struct heap_header*) + (size_t)heap->idx) >= heap->start_addr) return; + + uint32_t iterator = 0, pos; + while (iterator < heap->idxused && heap->idx[iterator]->size < e->size) { + if (heap->idx[iterator] == e) return; + iterator++; + } + if (iterator == heap->idxused) { + heap->idx[heap->idxused++] = e; + } else { + pos = iterator; + iterator = heap->idxused; + while (iterator > pos) { + heap->idx[iterator] = heap->idx[iterator - 1]; + iterator--; + } + heap->idxused++; + heap->idx[pos] = e; + } +} + +static void heapIdx_remove(struct heap *heap, struct heap_header *e) { + uint32_t iterator; + for (iterator = 0; iterator < heap->idxused; iterator++) { + if (heap->idx[iterator] == e) break; + } + if (iterator == heap->idxused) return; + heap->idxused--; + while (iterator < heap->idxused) { + heap->idx[iterator] = heap->idx[iterator + 1]; + iterator++; + } +} + +/* ******************** HEAP CONTENTS ********************* */ + +int heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize) { + if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000; + + heap->start_addr = start + idxsize; + heap->end_addr = start + idxsize + datasize; + heap->max_end = start + idxsize + maxdatasize; + + if (setheapseg(heap, start, heap->end_addr, 0)) return -1; + + heap->idx = (struct heap_header**)start; + heap->idxused = 0; + + struct heap_header *hole = (struct heap_header*) heap->start_addr; + hole->size = (heap->end_addr - heap->start_addr); + hole->magic = HEAP_MAGIC; + hole->is_hole = 1; + + struct heap_footer *hole_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer)); + hole_footer->header = hole; + hole_footer->magic = HEAP_MAGIC; + + heapIdx_insert(heap, hole); + return 0; +} + +static uint32_t heap_expand(struct heap *heap, size_t quantity) { + if (quantity & 0x0FFF) { + quantity = (quantity & 0xFFFFF000) + 0x1000; + } + + if (heap->end_addr + quantity > heap->max_end) return 0; + + size_t newEnd = heap->end_addr + quantity; + + if (setheapseg(heap, (size_t)heap->idx, newEnd, heap->end_addr)) return 0; //failed to bigger segment + + struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer)); + struct heap_header *last_header = last_footer->header; + if (last_header->is_hole) { + heapIdx_remove(heap, last_header); + last_header->size += quantity; + + last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer)); + last_footer->magic = HEAP_MAGIC; + last_footer->header = last_header; + + heapIdx_insert(heap, last_header); + } else { + last_header = (struct heap_header*)heap->end_addr; + last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer)); + + last_header->is_hole = 1; + last_header->magic = HEAP_MAGIC; + last_header->size = quantity; + + last_footer->magic = HEAP_MAGIC; + last_footer->header = last_header; + + heapIdx_insert(heap, last_header); + } + + heap->end_addr = newEnd; + + return 1; +} + +static void heap_contract(struct heap *heap) { + struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer)); + struct heap_header *last_header = last_footer->header; + + if (last_header->is_hole == 0) return; + + size_t quantity = 0; + while ((heap->end_addr - heap->start_addr) - quantity > HEAP_MIN_SIZE && + (last_header->size - quantity) > 0x1000) + quantity += 0x1000; + if (quantity == 0) return; + + size_t newEnd = heap->end_addr - quantity; + + if (setheapseg(heap, (size_t)heap->idx, newEnd, heap->end_addr)) return; //error ocurred + + heapIdx_remove(heap, last_header); + last_header->size -= quantity; + last_footer = (struct heap_footer*)((size_t)last_footer - quantity); + last_footer->magic = HEAP_MAGIC; + last_footer->header = last_header; + heapIdx_insert(heap, last_header); + + heap->end_addr = newEnd; +} + +void* heap_alloc(struct heap *heap, size_t sz) { + size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer); + uint32_t iterator = 0; + + while (iterator < heap->idxused) { + if (heap->idx[iterator]->size >= newsize) break; + iterator++; + } + + if (iterator == heap->idxused) { //No hole is big enough + if (heap_expand(heap, (sz & 0xFFFFF000) + 0x1000) == 0) return 0; //FAILED + return heap_alloc(heap, sz); + } + + struct heap_header *loc = heap->idx[iterator]; + struct heap_footer *footer = (struct heap_footer*)((size_t)loc + loc->size - sizeof(struct heap_footer)); + loc->is_hole = 0; + heapIdx_remove(heap, loc); + + //If we have enough space to create a USEFUL new hole next to the allocated block, do it. + //If we do not, we might return a block that is a few bytes bigger than neede. + if (loc->size > (newsize + sizeof(struct heap_header) + sizeof(struct heap_footer))) { + loc->size = newsize; + + //Write footer for block we return + struct heap_footer *newfooter = (struct heap_footer*)((size_t)loc + newsize - sizeof(struct heap_footer)); + newfooter->header = loc; + newfooter->magic = HEAP_MAGIC; + + //Write header for new hole we create + struct heap_header *nextloc = (struct heap_header*)((size_t)loc + newsize); + nextloc->is_hole = 1; + nextloc->magic = HEAP_MAGIC; + nextloc->size = ((size_t)footer - (size_t)nextloc + sizeof(struct heap_footer)); + footer->header = nextloc; //Update footer + footer->magic = HEAP_MAGIC; + + heapIdx_insert(heap, nextloc); + } + + return (void*)((size_t)loc + sizeof(struct heap_header)); +} + +void heap_free(struct heap *heap, void* ptr) { + if (ptr == 0) return; + if ((size_t)ptr < heap->start_addr || (size_t)ptr > heap->end_addr) return; + + struct heap_header *header = (struct heap_header*)((size_t)ptr - sizeof(struct heap_header)); + struct heap_footer *footer = (struct heap_footer*)((size_t)header + header->size - sizeof(struct heap_footer)); + if (header->magic != HEAP_MAGIC || footer->magic != HEAP_MAGIC) return; + + //Unify left + struct heap_footer *prev_footer = (struct heap_footer*)((size_t)header - sizeof(struct heap_footer)); + if (prev_footer->magic == HEAP_MAGIC && prev_footer->header->is_hole) { + header = prev_footer->header; + heapIdx_remove(heap, header); + + footer->header = header; + header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer)); + } + + //Unify right + struct heap_header *next_header = (struct heap_header*)((size_t)footer + sizeof(struct heap_footer)); + if (next_header->magic == HEAP_MAGIC && next_header->is_hole) { + heapIdx_remove(heap, next_header); + footer = (struct heap_footer*)((size_t)footer + next_header->size); + + footer->header = header; + header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer)); + } + + header->is_hole = 1; + + heapIdx_insert(heap, header); + + if ((size_t)footer == (heap->end_addr - sizeof(struct heap_footer)) && + header->size >= 0x2000 && (heap->end_addr - heap->start_addr > HEAP_MIN_SIZE)) { + heap_contract(heap); + } +} diff --git a/src/library/gc/object.c b/src/library/gc/object.c new file mode 100644 index 0000000..59b986b --- /dev/null +++ b/src/library/gc/object.c @@ -0,0 +1,178 @@ +#include +#include +#include + +Server procServer; +static Server* servers = 0; + +static method_handler getHandler(Server *o, uint32_t m); +static struct method_ret checkIfHandles(struct method_data *d); + +void objsrv_init() { + procServer.id = 0; + procServer.methods = 0; + procServer.next = 0; + procServer.data = 0; + servers = &procServer; + srv_addHandler(&procServer, M_HANDLECHECK_BIVV, checkIfHandles); +} + +void srv_handleAll() { + Server *i = servers; + while (i) { + srv_handle(i, HA_ONCE); + i = i->next; + } +} + +void srv_handle(Server *o, int act) { + int i; + + if (act == HA_LOOP) { + while (1) srv_handle(o, HA_WAIT); + } else { + struct user_request rq; + int v = request_get(o->id, &rq, (act == HA_WAIT)); + if (v == 0) { + method_handler m = getHandler(o, rq.func); + if (m == 0) { + if (rq.isBlocking) { + request_answer(o->id, 0, 0, ME_UNHANDLED); + } + } else { + struct method_data md; + md.func = rq.func; + md.blocking = rq.isBlocking; + md.obj = o; + //get parameters + for (i = 0; i < 3; i++) { + md.parameters[i].type = (rq.func >> (28 - (2 * i))) & 3; + switch (md.parameters[i].type) { + case PT_LONG: + case PT_OBJDESC: + md.parameters[i].val.i = rq.params[i]; + break; + case PT_SHM: //all the fuss about keepShm only applies to messages. + md.parameters[i].keepShm = 1; //if local memory or if nothing, do not unmap it + if (rq.params[i] == 0) { //TODO : map shm (shm manager) !!! + md.parameters[i].val.p = 0; + //md.parameters[i].keepShm = 0; //we had to map it, so mark it to be unmapped + } else { + md.parameters[i].val.p = (void*)rq.params[i]; + } + break; + } + } + + struct method_ret ret = m(&md); //Call method + if (rq.isBlocking) { + uint32_t a = 0, b = 0; + if (ret.type == PT_OBJDESC || ret.type == PT_LONG) a = ret.i; + if (ret.type == PT_LONGLONG) a = (uint32_t)ret.l, b = (uint32_t)((uint64_t)ret.l >> 32); + request_answer(o->id, a, b, ret.status); + } else { + for (i = 0; i < 3; i++) { + if (md.parameters[i].type == PT_SHM && md.parameters[i].keepShm == 0) { + //TODO : unmap shm + } + } + } + } + } + } +} + +void srv_addHandler(Server* o, uint32_t method, method_handler h) { + struct method_srv *s = malloc(sizeof(struct method_srv)); + s->id = method; + s->h = h; + s->next = o->methods; + o->methods = s; +} + +Server *srv_create() { + Server *s = malloc(sizeof(Server)); + s->id = object_create(); + s->methods = 0; + s->data = 0; + s->next = servers; + srv_addHandler(s, M_HANDLECHECK_BIVV, checkIfHandles); + servers = s; + return s; +} + +void srv_delete(Server* s) { + //remove s from servers + if (servers == s) { + servers = s->next; + } else { + Server *i = servers; + while (i->next != 0) { + if (i->next == s) { + i->next = s->next; + break; + } + i = i->next; + } + } + //close s + object_close(s->id); + //free methods for s + while (s->methods != 0) { + struct method_srv *m = s->methods->next; + free(s->methods); + s->methods = m; + } + //free s + free(s); +} + +// internal use + +method_handler getHandler(Server *o, uint32_t m) { + struct method_srv *i = o->methods; + while (i) { + if (i->id == m) return i->h; + i = i->next; + } + return 0; +} + +struct method_ret checkIfHandles(struct method_data *d) { + if (getHandler(d->obj, d->parameters[0].val.i) == 0) { + return mr_long(0); + } + return mr_long(1); +} + +// ***************************** HELPER FUNCTIONS FOR RETRUN VALUES + +struct method_ret mr_long(int val) { + struct method_ret r; r.status = 0; r.type = PT_LONG; r.i = val; + return r; +} + +struct method_ret mr_llong(int64_t val) { + struct method_ret r; r.status = 0; r.type = PT_LONGLONG; r.l = val; + return r; +} + +struct method_ret mr_obj(Object* obj) { + struct method_ret r; r.status = 0; r.type = PT_OBJDESC; r.i = obj->id; + return r; +} + +struct method_ret mr_srv(Server* obj) { + struct method_ret r; r.status = 0; r.type = PT_OBJDESC; r.i = obj->id; + return r; +} + +struct method_ret mr_void() { + struct method_ret r; r.status = 0; r.type = PT_VOID; + return r; +} + +struct method_ret mr_err(int error) { + struct method_ret r; r.status = error; r.type = PT_VOID; r.l = 0; + return r; +} diff --git a/src/library/gc/syscall.c b/src/library/gc/syscall.c index 8fd1554..e7d77a0 100644 --- a/src/library/gc/syscall.c +++ b/src/library/gc/syscall.c @@ -66,8 +66,8 @@ int request_has(int descriptor) { return call(14, descriptor, 0, 0, 0, 0); } -void request_answer(int descriptor, int answer1, int answer2) { - call(15, descriptor, answer1, answer2, 0, 0); +void request_answer(int descriptor, uint32_t answer1, uint32_t answer2, int errcode) { + call(15, descriptor, answer1, answer2, errcode, 0); } int request_mapShm(int descriptor, size_t offset, int number) { @@ -81,3 +81,7 @@ int request(int descriptor, struct user_sendrequest *rq) { int send_msg(int descriptor, struct user_sendrequest *rq) { return call(18, descriptor, (size_t)rq, 0, 0, 0); } + +int proc_setheap(size_t start, size_t end) { + return call(19, start, end, 0, 0, 0); +} diff --git a/src/library/link.ld b/src/library/link.ld index 17c944a..be5e028 100644 --- a/src/library/link.ld +++ b/src/library/link.ld @@ -2,7 +2,7 @@ ENTRY (start) INPUT (grapes.o) SECTIONS{ - . = 0x10000000; + . = 0x100000; .text : { *(.text) diff --git a/src/library/start.c b/src/library/start.c index b3c5541..c9a7acc 100644 --- a/src/library/start.c +++ b/src/library/start.c @@ -3,6 +3,7 @@ extern int main(); void start() { + objsrv_init(); int ret = main(); process_exit(ret); } diff --git a/src/modules/test/main.c b/src/modules/test/main.c index df8b2ef..49dc50e 100644 --- a/src/modules/test/main.c +++ b/src/modules/test/main.c @@ -1,36 +1,57 @@ #include +#include +#include #define FACTOR 4 int obj = -1; +struct method_ret nulhandle(struct method_data *d) { + if (d->blocking) printk("[test:2?] Handling a request.\n"); + else printk("[test:2?] Handling a message.\n"); + return mr_void(); +} + void thread2(void* d) { printk("[test:2] Creating new object...\n"); - obj = object_create(); - struct user_request rq; + Server *s = srv_create(); + srv_addHandler(s, 0x00000010, nulhandle); + obj = s->id; while (1) { printk("[test:2] Waiting for a request...\n"); - request_get(obj, &rq, 1); - if (rq.isBlocking) { - printk("[test:2] Got request. Answering...\n"); - request_answer(obj, 42, 0); - } else { - printk("[test:2] Got message. Ignoring it.\n"); - } + srv_handle(s, HA_WAIT); } } int main() { + int i; + printk("[test:1] Hi world !\n"); printk("[test:1] Creating new thread...\n"); thread_new(thread2, 0); while (obj == -1); printk("[test:1] Object was created. Sending request...\n"); struct user_sendrequest sr; - sr.func = 0x80000001; + sr.func = 0x00000010; request(obj, &sr); printk("[test:1] Got answer. Sending message...\n"); send_msg(obj, &sr); + + printk("[test:1] testing malloc and free..."); + int* v = malloc(10 * sizeof(int)); + if (v == 0) printk("zero"); + int* vv = malloc(10 * sizeof(int)); + for (i = 0; i < 10; i++) { v[i] = i * 1243; } + for (i = 0; i < 10; i++) { vv[i] = i * 2; } + for (i = 0; i < 10; i++) { + if (v[i] != i * 1243) printk("FAIL"); + } + for (i = 0; i < 10; i++) { + if (vv[i] != i * 2) printk("fail"); + } + free(v); free(vv); + printk("nothing bad happened :)\n"); + printk("[test:1] HAHA !!! Death in 10 seconds!\n"); thread_sleep(10000); return 0; -- cgit v1.2.3