summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/memlayout.txt8
-rw-r--r--doc/method.txt1
-rw-r--r--doc/roadmap.txt12
-rw-r--r--doc/syscalls.txt4
-rw-r--r--src/include/gc/mem.h9
-rw-r--r--src/include/gc/obj.h14
-rw-r--r--src/include/gc/server.h79
-rw-r--r--src/include/gc/syscall.h4
-rw-r--r--src/include/gm/method.h22
-rw-r--r--src/kernel/ipc/request.c36
-rw-r--r--src/kernel/ipc/request.h4
-rw-r--r--src/kernel/linker/elf.c6
-rw-r--r--src/kernel/mem/paging.c1
-rw-r--r--src/kernel/mem/paging.h2
-rw-r--r--src/kernel/mem/seg.c21
-rw-r--r--src/kernel/mem/seg.h1
-rw-r--r--src/kernel/task/idt.h1
-rw-r--r--src/kernel/task/idt_.asm6
-rw-r--r--src/kernel/task/syscall.c2
-rw-r--r--src/kernel/task/task.c24
-rw-r--r--src/kernel/task/task.h3
-rw-r--r--src/library/Makefile2
-rw-r--r--src/library/gc/mem.c262
-rw-r--r--src/library/gc/object.c178
-rw-r--r--src/library/gc/syscall.c8
-rw-r--r--src/library/link.ld2
-rw-r--r--src/library/start.c1
-rw-r--r--src/modules/test/main.c41
28 files changed, 716 insertions, 38 deletions
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_<method_name>_<ret><param1><param2><param3>
+ * 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 <gc/server.h>
+#include <gm/method.h>
+#include <gc/mem.h>
+
+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 <gc/syscall.h>
+#include <gc/mem.h>
+#include <gc/server.h>
#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;